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


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

#include "pgpX509Cert_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 AlgorithmIdentifier
 ******************************************************************/

size_t pgpasn_SizeofAlgorithmIdentifierInternal(
    PGPASN_AlgorithmIdentifier *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            pgpasn_SizeofOBJECT_IDInternal(&asnstruct->algorithm, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofANYInternal(asnstruct->parameters, PGPASN_TRUE, PGPASN_FALSE) ;

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;

} /* pgpasn_SizeofAlgorithmIdentifierInternal */

void pgpasn_DropInPlaceAlgorithmIdentifier(
    PGPASN_CONTEXT *ctx,
    PGPASN_AlgorithmIdentifier *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    pgpasn_DropInPlaceOBJECT_ID(ctx, &(f->algorithm));
    pgpasn_FreeANY(ctx, f->parameters);
    f->parameters = NULL;
} /* pgpasn_DropInPlaceAlgorithmIdentifier */

size_t pgpasn_PackAlgorithmIdentifierInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_AlgorithmIdentifier *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofAlgorithmIdentifier(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

  do {

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

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

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackAlgorithmIdentifierInternal */

size_t pgpasn_UnpkInPlaceAlgorithmIdentifier(
    PGPASN_CONTEXT *ctx,
    PGPASN_AlgorithmIdentifier *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;

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

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

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

    PGPASN_TRACE_INCR_LEVEL;
  do {

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

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

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceAlgorithmIdentifier */

size_t pgpasn_UnpackAlgorithmIdentifierInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_AlgorithmIdentifier **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_AlgorithmIdentifier *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewAlgorithmIdentifier(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceAlgorithmIdentifier(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeAlgorithmIdentifier(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackAlgorithmIdentifierInternal */


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

size_t pgpasn_SizeofAttributeTypeAndValueInternal(
    PGPASN_AttributeTypeAndValue *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            pgpasn_SizeofAttributeTypeInternal(&asnstruct->type, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofAttributeValueInternal(&asnstruct->value, PGPASN_TRUE, PGPASN_FALSE) ;

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;

} /* pgpasn_SizeofAttributeTypeAndValueInternal */

void pgpasn_DropInPlaceAttributeTypeAndValue(
    PGPASN_CONTEXT *ctx,
    PGPASN_AttributeTypeAndValue *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    pgpasn_DropInPlaceAttributeType(ctx, &(f->type));
    pgpasn_DropInPlaceAttributeValue(ctx, &(f->value));
} /* pgpasn_DropInPlaceAttributeTypeAndValue */

size_t pgpasn_PackAttributeTypeAndValueInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_AttributeTypeAndValue *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofAttributeTypeAndValue(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

  do {

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

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

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackAttributeTypeAndValueInternal */

size_t pgpasn_UnpkInPlaceAttributeTypeAndValue(
    PGPASN_CONTEXT *ctx,
    PGPASN_AttributeTypeAndValue *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;

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

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

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

    PGPASN_TRACE_INCR_LEVEL;
  do {

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

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

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceAttributeTypeAndValue */

size_t pgpasn_UnpackAttributeTypeAndValueInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_AttributeTypeAndValue **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_AttributeTypeAndValue *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewAttributeTypeAndValue(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceAttributeTypeAndValue(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeAttributeTypeAndValue(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackAttributeTypeAndValueInternal */


/******************************************************************
 * Routines for AttributeValues
 ******************************************************************/

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

    if (asnstruct == NULL)
        return 0;

    lth = asnstruct->n;
    if (lth > PGPASN_MAX_AttributeValues)
        lth = PGPASN_MAX_AttributeValues;	/* clamp it */
    for (i=0;i<lth;i++)
        body_size += pgpasn_SizeofAttributeValueInternal((asnstruct->elt)[i], PGPASN_TRUE, PGPASN_FALSE);

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;
} /* pgpasn_SizeofAttributeValuesInternal */

void pgpasn_DropInPlaceAttributeValues(
    PGPASN_CONTEXT *ctx,
    PGPASN_AttributeValues *f)
{
    long i, lth;

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

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

size_t pgpasn_PackAttributeValuesInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_AttributeValues *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;
    PGPASN_VariableBlock temp[PGPASN_MAX_AttributeValues];

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

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

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

    datasize = pgpasn_SizeofAttributeValues(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

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

    else {

        /* calculate lengths and max */
        for (i=0; i<numElem; i++) {
            length = pgpasn_SizeofAttributeValue(ctx, (asnstruct->elt)[i], PGPASN_TRUE);
            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 *)PGPASN_Alloc(ctx->memMgr, max);
            memset(temp[i].val, 0, max);
            (void) pgpasn_PackAttributeValueInternal(ctx, temp[i].val,
                          max, (asnstruct->elt)[i],
                          PGPASN_ID_AttributeValue, erret );
            if (*erret != 0) {
                for (j=0; j<i; j++)
                    PGPASN_Free(ctx->memMgr, temp[j].val);
                return 0;
            }
        }

        /* sort and look for duplicates */
        qsort(temp, numElem, sizeof(PGPASN_VariableBlock), PGPASN_CompareElems);
        for (i=0; i<(numElem-1); i++)
            if (memcmp(temp[i].val, temp[i+1].val, max) == 0) {
                PGPASN_ERR(kPGPASNError_ErrPackSETOFUnsortable);
                for (j=0; j<i; j++)
                    PGPASN_Free(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;
            PGPASN_Free(ctx->memMgr, temp[i].val);
        }
    }

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackAttributeValuesInternal */

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

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x31, "SET OF", "AttributeValues");

    if (erret == NULL) return 0;

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

    bytesused += PGPASN_GetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
            asnstruct->n = -1 ; /* note where (-1 treated as 0) */
            PGPASN_TRACE_DECR_LEVEL;
            return 0;
        }
    }

    for (i=0; (i < PGPASN_MAX_AttributeValues) && (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] = pgpasn_NewAttributeValue(ctx);
        if (asnstruct->elt[i] == NULL) {
            PGPASN_ERR(kPGPASNError_ErrOutOfMemory);
            break;
        }
        asnstruct->n = i+1 ; /* note the new element */
        bytesused += pgpasn_UnpkInPlaceAttributeValue(ctx, asnstruct->elt[i],
                          buf+bytesused, localsize-bytesused,
                          PGPASN_ID_AttributeValue, erret);
        if (*erret != 0)
            break;
    } /* for */

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceAttributeValues */

size_t pgpasn_UnpackAttributeValuesInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_AttributeValues **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_AttributeValues *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewAttributeValues(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceAttributeValues(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeAttributeValues(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackAttributeValuesInternal */


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

size_t pgpasn_SizeofBasicConstraintsInternal(
    PGPASN_BasicConstraints *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            pgpasn_SizeofBOOLEANInternal(asnstruct->cA, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofINTEGERInternal(asnstruct->pathLenConstraint, PGPASN_TRUE, PGPASN_FALSE) ;

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;

} /* pgpasn_SizeofBasicConstraintsInternal */

void pgpasn_DropInPlaceBasicConstraints(
    PGPASN_CONTEXT *ctx,
    PGPASN_BasicConstraints *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    pgpasn_FreeBOOLEAN(ctx, f->cA);
    f->cA = NULL;
    pgpasn_FreeINTEGER(ctx, f->pathLenConstraint);
    f->pathLenConstraint = NULL;
} /* pgpasn_DropInPlaceBasicConstraints */

size_t pgpasn_PackBasicConstraintsInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_BasicConstraints *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofBasicConstraints(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

  do {

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

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

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackBasicConstraintsInternal */

size_t pgpasn_UnpkInPlaceBasicConstraints(
    PGPASN_CONTEXT *ctx,
    PGPASN_BasicConstraints *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;

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

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

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

    PGPASN_TRACE_INCR_LEVEL;
  do {

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

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

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceBasicConstraints */

size_t pgpasn_UnpackBasicConstraintsInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_BasicConstraints **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_BasicConstraints *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewBasicConstraints(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceBasicConstraints(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeBasicConstraints(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackBasicConstraintsInternal */


/******************************************************************
 * Routines for CertificateValidityDate
 ******************************************************************/

size_t pgpasn_SizeofCertificateValidityDateInternal(
    PGPASN_CertificateValidityDate *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    switch (asnstruct->CHOICE_field_type) {
      case PGPASN_ID_UTCTime:
      case 0x20|PGPASN_ID_UTCTime:
        body_size = pgpasn_SizeofUTCTimeInternal((PGPASN_UTCTime *)(asnstruct->data), outerSizeFlag, expTaggedFlag);
        break;

      case PGPASN_ID_GeneralizedTime:
      case 0x20|PGPASN_ID_GeneralizedTime:
        body_size = pgpasn_SizeofGeneralizedTimeInternal((PGPASN_GeneralizedTime *)(asnstruct->data), outerSizeFlag, expTaggedFlag);
        break;

      default:
        break;

    } /* switch */

    return (body_size);
} /* pgpasn_SizeofCertificateValidityDateInternal */

void pgpasn_DropInPlaceCertificateValidityDate(
    PGPASN_CONTEXT *ctx,
    PGPASN_CertificateValidityDate *f)
{
    if (ctx == NULL) return;
    if (f == NULL) return;

    switch(f->CHOICE_field_type) {

    case PGPASN_ID_UTCTime:
    case 0x20|PGPASN_ID_UTCTime:
        pgpasn_FreeUTCTime(ctx, (PGPASN_UTCTime *)( f->data ));
        break;
    case PGPASN_ID_GeneralizedTime:
    case 0x20|PGPASN_ID_GeneralizedTime:
        pgpasn_FreeGeneralizedTime(ctx, (PGPASN_GeneralizedTime *)( f->data ));
        break;
    default:
        break;
    } /* switch */

} /* pgpasn_DropInPlaceCertificateValidityDate */

size_t pgpasn_PackCertificateValidityDateInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_CertificateValidityDate *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofCertificateValidityDate(ctx, asnstruct, PGPASN_TRUE);
    if (datasize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

    case PGPASN_ID_UTCTime:
        bytesused += pgpasn_PackUTCTimeInternal(ctx, buf+bytesused, buflen-bytesused,
                     (PGPASN_UTCTime *)(asnstruct->data),
                     PGPASN_ID_UTCTime,
                     erret);
        break;

    case PGPASN_ID_GeneralizedTime:
        bytesused += pgpasn_PackGeneralizedTimeInternal(ctx, buf+bytesused, buflen-bytesused,
                     (PGPASN_GeneralizedTime *)(asnstruct->data),
                     PGPASN_ID_GeneralizedTime,
                     erret);
        break;

    default:
        PGPASN_ERR( kPGPASNError_ErrChoiceBadType );
        break;
    } /* switch */

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

  return bytesused;
} /* pgpasn_PackCertificateValidityDateInternal */

size_t pgpasn_UnpkInPlaceCertificateValidityDate(
     PGPASN_CONTEXT *ctx,
     PGPASN_CertificateValidityDate *asnstruct,/* output block */
     const unsigned char *buf,
     size_t buflen,
     unsigned char tag,
     int *erret)
{
    (void)tag; /* unused */


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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        return 0;
    }

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

    switch (*buf) {

    /* utcTime */
    case PGPASN_ID_UTCTime:
    case 0x20|PGPASN_ID_UTCTime:
        asnstruct->CHOICE_field_type = *buf;
        asnstruct->data = (void *)pgpasn_NewUTCTime(ctx);
        if (asnstruct->data == NULL) {
            PGPASN_ERR(kPGPASNError_ErrOutOfMemory);
            return 0;
        }
        return (pgpasn_UnpkInPlaceUTCTime(ctx, (PGPASN_UTCTime *)(asnstruct->data),
                    buf, buflen,
                    PGPASN_ID_UTCTime, erret));
        /*NOTREACHED*/
        break;

    /* generalTime */
    case PGPASN_ID_GeneralizedTime:
    case 0x20|PGPASN_ID_GeneralizedTime:
        asnstruct->CHOICE_field_type = *buf;
        asnstruct->data = (void *)pgpasn_NewGeneralizedTime(ctx);
        if (asnstruct->data == NULL) {
            PGPASN_ERR(kPGPASNError_ErrOutOfMemory);
            return 0;
        }
        return (pgpasn_UnpkInPlaceGeneralizedTime(ctx, (PGPASN_GeneralizedTime *)(asnstruct->data),
                    buf, buflen,
                    PGPASN_ID_GeneralizedTime, erret));
        /*NOTREACHED*/
        break;

    default:
        PGPASN_ERR(kPGPASNError_ErrChoiceBadType);
        return 0;

    } /* switch */

} /* pgpasn_UnpkInPlaceCertificateValidityDate */

size_t pgpasn_UnpackCertificateValidityDateInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_CertificateValidityDate **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_CertificateValidityDate *local = NULL ;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

    local = pgpasn_NewCertificateValidityDate(ctx) ; /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceCertificateValidityDate(ctx, local, buf, buflen, tag, erret);
    if (*erret == kPGPASNError_ErrChoiceBadType) {
        *erret = 0;
        if (local != NULL) pgpasn_FreeCertificateValidityDate(ctx, local);
        return 0;
    }
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeCertificateValidityDate(ctx, local);
        return 0;
    }

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


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

size_t pgpasn_SizeofContentInfoInternal(
    PGPASN_ContentInfo *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            pgpasn_SizeofContentTypeInternal(&asnstruct->contentType, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofANYInternal(asnstruct->content, PGPASN_TRUE, PGPASN_TRUE) ;

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;

} /* pgpasn_SizeofContentInfoInternal */

void pgpasn_DropInPlaceContentInfo(
    PGPASN_CONTEXT *ctx,
    PGPASN_ContentInfo *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    pgpasn_DropInPlaceContentType(ctx, &(f->contentType));
    pgpasn_FreeANY(ctx, f->content);
    f->content = NULL;
} /* pgpasn_DropInPlaceContentInfo */

size_t pgpasn_PackContentInfoInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_ContentInfo *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofContentInfo(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

  do {

    /* field contentType of ContentInfo */
    bytesused += pgpasn_PackContentTypeInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->contentType), PGPASN_ID_ContentType, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field content of ContentInfo */
    if (asnstruct->content != NULL) { /* optional */
        bytesused += PGPASN_PutTag(buf+bytesused, 0xa0 | 0x00, pgpasn_SizeofANY(ctx, asnstruct->content, PGPASN_TRUE));
        bytesused += pgpasn_PackANYInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->content, PGPASN_ID_ANY, erret) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackContentInfoInternal */

size_t pgpasn_UnpkInPlaceContentInfo(
    PGPASN_CONTEXT *ctx,
    PGPASN_ContentInfo *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;

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "ContentInfo" );

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

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

    PGPASN_TRACE_INCR_LEVEL;
  do {

    /* field contentType of ContentInfo */
    bytesused += pgpasn_UnpkInPlaceContentType(ctx, &(asnstruct->contentType), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_ContentType, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field content of ContentInfo */
    if (!indef && bytesused >= localsize) {
        PGPASN_TRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PGPASN_TRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    { /* local declaration block*/
        size_t taggeddatasize;
        size_t taggedlocalsize;
        size_t used;

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

        if ((int)taggeddatasize == -1 && used != 0) {
            PGPASN_TRACE_PRINT_TAG(0xa0|0x00, 0x00);
            PGPASN_TRACE_INCR_LEVEL;
            if (asnstruct->content != NULL)
                pgpasn_FreeANY(ctx, asnstruct->content);
            bytesused += pgpasn_UnpackANYInternal(ctx, &(asnstruct->content),
                    buf+bytesused, localsize-bytesused, PGPASN_ID_ANY, erret);
            PGPASN_TRACE_DECR_LEVEL;
            if ( *(buf+bytesused) != 0x00 &&
                 *(buf+bytesused+1) != 0x00 ) {
                PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
                break;
            }
            bytesused += 2;
        }

        else if (taggeddatasize > 0 && used != 0) {
            taggedlocalsize = bytesused + taggeddatasize;
            PGPASN_TRACE_PRINT_TAG(0xa0|0x00, 0x00);
            PGPASN_TRACE_INCR_LEVEL;
            if (asnstruct->content != NULL)
                pgpasn_FreeANY(ctx, asnstruct->content);
            bytesused += pgpasn_UnpackANYInternal(ctx, &(asnstruct->content),
                       buf+bytesused, localsize-bytesused, PGPASN_ID_ANY, erret);
            PGPASN_TRACE_DECR_LEVEL;
            if (bytesused != taggedlocalsize) {
                PGPASN_ERR(kPGPASNError_ErrUnpackTaggedLth);
                break;
            }
        }
    } /* for the local declaration block */
    if (bytesused > localsize || *erret != 0)
        break;

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceContentInfo */

size_t pgpasn_UnpackContentInfoInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_ContentInfo **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_ContentInfo *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewContentInfo(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceContentInfo(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeContentInfo(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackContentInfoInternal */


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

size_t pgpasn_SizeofDirectoryStringInternal(
    PGPASN_DirectoryString *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    switch (asnstruct->CHOICE_field_type) {
      case PGPASN_ID_T61String:
      case 0x20|PGPASN_ID_T61String:
        body_size = pgpasn_SizeofT61StringInternal((PGPASN_T61String *)(asnstruct->data), outerSizeFlag, expTaggedFlag);
        break;

      case PGPASN_ID_PrintableString:
      case 0x20|PGPASN_ID_PrintableString:
        body_size = pgpasn_SizeofPrintableStringInternal((PGPASN_PrintableString *)(asnstruct->data), outerSizeFlag, expTaggedFlag);
        break;

      case PGPASN_ID_UniversalString:
      case 0x20|PGPASN_ID_UniversalString:
        body_size = pgpasn_SizeofUniversalStringInternal((PGPASN_UniversalString *)(asnstruct->data), outerSizeFlag, expTaggedFlag);
        break;

      case PGPASN_ID_UTF8String:
      case 0x20|PGPASN_ID_UTF8String:
        body_size = pgpasn_SizeofUTF8StringInternal((PGPASN_UTF8String *)(asnstruct->data), outerSizeFlag, expTaggedFlag);
        break;

      case PGPASN_ID_BMPString:
      case 0x20|PGPASN_ID_BMPString:
        body_size = pgpasn_SizeofBMPStringInternal((PGPASN_BMPString *)(asnstruct->data), outerSizeFlag, expTaggedFlag);
        break;

      case PGPASN_ID_IA5String:
      case 0x20|PGPASN_ID_IA5String:
        body_size = pgpasn_SizeofIA5StringInternal((PGPASN_IA5String *)(asnstruct->data), outerSizeFlag, expTaggedFlag);
        break;

      default:
        break;

    } /* switch */

    return (body_size);
} /* pgpasn_SizeofDirectoryStringInternal */

void pgpasn_DropInPlaceDirectoryString(
    PGPASN_CONTEXT *ctx,
    PGPASN_DirectoryString *f)
{
    if (ctx == NULL) return;
    if (f == NULL) return;

    switch(f->CHOICE_field_type) {

    case PGPASN_ID_T61String:
    case 0x20|PGPASN_ID_T61String:
        pgpasn_FreeT61String(ctx, (PGPASN_T61String *)( f->data ));
        break;
    case PGPASN_ID_PrintableString:
    case 0x20|PGPASN_ID_PrintableString:
        pgpasn_FreePrintableString(ctx, (PGPASN_PrintableString *)( f->data ));
        break;
    case PGPASN_ID_UniversalString:
    case 0x20|PGPASN_ID_UniversalString:
        pgpasn_FreeUniversalString(ctx, (PGPASN_UniversalString *)( f->data ));
        break;
    case PGPASN_ID_UTF8String:
    case 0x20|PGPASN_ID_UTF8String:
        pgpasn_FreeUTF8String(ctx, (PGPASN_UTF8String *)( f->data ));
        break;
    case PGPASN_ID_BMPString:
    case 0x20|PGPASN_ID_BMPString:
        pgpasn_FreeBMPString(ctx, (PGPASN_BMPString *)( f->data ));
        break;
    case PGPASN_ID_IA5String:
    case 0x20|PGPASN_ID_IA5String:
        pgpasn_FreeIA5String(ctx, (PGPASN_IA5String *)( f->data ));
        break;
    default:
        break;
    } /* switch */

} /* pgpasn_DropInPlaceDirectoryString */

size_t pgpasn_PackDirectoryStringInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_DirectoryString *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofDirectoryString(ctx, asnstruct, PGPASN_TRUE);
    if (datasize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

    case PGPASN_ID_T61String:
        bytesused += pgpasn_PackT61StringInternal(ctx, buf+bytesused, buflen-bytesused,
                     (PGPASN_T61String *)(asnstruct->data),
                     PGPASN_ID_T61String,
                     erret);
        break;

    case PGPASN_ID_PrintableString:
        bytesused += pgpasn_PackPrintableStringInternal(ctx, buf+bytesused, buflen-bytesused,
                     (PGPASN_PrintableString *)(asnstruct->data),
                     PGPASN_ID_PrintableString,
                     erret);
        break;

    case PGPASN_ID_UniversalString:
        bytesused += pgpasn_PackUniversalStringInternal(ctx, buf+bytesused, buflen-bytesused,
                     (PGPASN_UniversalString *)(asnstruct->data),
                     PGPASN_ID_UniversalString,
                     erret);
        break;

    case PGPASN_ID_UTF8String:
        bytesused += pgpasn_PackUTF8StringInternal(ctx, buf+bytesused, buflen-bytesused,
                     (PGPASN_UTF8String *)(asnstruct->data),
                     PGPASN_ID_UTF8String,
                     erret);
        break;

    case PGPASN_ID_BMPString:
        bytesused += pgpasn_PackBMPStringInternal(ctx, buf+bytesused, buflen-bytesused,
                     (PGPASN_BMPString *)(asnstruct->data),
                     PGPASN_ID_BMPString,
                     erret);
        break;

    case PGPASN_ID_IA5String:
        bytesused += pgpasn_PackIA5StringInternal(ctx, buf+bytesused, buflen-bytesused,
                     (PGPASN_IA5String *)(asnstruct->data),
                     PGPASN_ID_IA5String,
                     erret);
        break;

    default:
        PGPASN_ERR( kPGPASNError_ErrChoiceBadType );
        break;
    } /* switch */

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

  return bytesused;
} /* pgpasn_PackDirectoryStringInternal */

size_t pgpasn_UnpkInPlaceDirectoryString(
     PGPASN_CONTEXT *ctx,
     PGPASN_DirectoryString *asnstruct,/* output block */
     const unsigned char *buf,
     size_t buflen,
     unsigned char tag,
     int *erret)
{
    (void)tag; /* unused */


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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        return 0;
    }

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

    switch (*buf) {

    /* teletexString */
    case PGPASN_ID_T61String:
    case 0x20|PGPASN_ID_T61String:
        asnstruct->CHOICE_field_type = *buf;
        asnstruct->data = (void *)pgpasn_NewT61String(ctx);
        if (asnstruct->data == NULL) {
            PGPASN_ERR(kPGPASNError_ErrOutOfMemory);
            return 0;
        }
        return (pgpasn_UnpkInPlaceT61String(ctx, (PGPASN_T61String *)(asnstruct->data),
                    buf, buflen,
                    PGPASN_ID_T61String, erret));
        /*NOTREACHED*/
        break;

    /* printableString */
    case PGPASN_ID_PrintableString:
    case 0x20|PGPASN_ID_PrintableString:
        asnstruct->CHOICE_field_type = *buf;
        asnstruct->data = (void *)pgpasn_NewPrintableString(ctx);
        if (asnstruct->data == NULL) {
            PGPASN_ERR(kPGPASNError_ErrOutOfMemory);
            return 0;
        }
        return (pgpasn_UnpkInPlacePrintableString(ctx, (PGPASN_PrintableString *)(asnstruct->data),
                    buf, buflen,
                    PGPASN_ID_PrintableString, erret));
        /*NOTREACHED*/
        break;

    /* universalString */
    case PGPASN_ID_UniversalString:
    case 0x20|PGPASN_ID_UniversalString:
        asnstruct->CHOICE_field_type = *buf;
        asnstruct->data = (void *)pgpasn_NewUniversalString(ctx);
        if (asnstruct->data == NULL) {
            PGPASN_ERR(kPGPASNError_ErrOutOfMemory);
            return 0;
        }
        return (pgpasn_UnpkInPlaceUniversalString(ctx, (PGPASN_UniversalString *)(asnstruct->data),
                    buf, buflen,
                    PGPASN_ID_UniversalString, erret));
        /*NOTREACHED*/
        break;

    /* utf8String */
    case PGPASN_ID_UTF8String:
    case 0x20|PGPASN_ID_UTF8String:
        asnstruct->CHOICE_field_type = *buf;
        asnstruct->data = (void *)pgpasn_NewUTF8String(ctx);
        if (asnstruct->data == NULL) {
            PGPASN_ERR(kPGPASNError_ErrOutOfMemory);
            return 0;
        }
        return (pgpasn_UnpkInPlaceUTF8String(ctx, (PGPASN_UTF8String *)(asnstruct->data),
                    buf, buflen,
                    PGPASN_ID_UTF8String, erret));
        /*NOTREACHED*/
        break;

    /* bmpString */
    case PGPASN_ID_BMPString:
    case 0x20|PGPASN_ID_BMPString:
        asnstruct->CHOICE_field_type = *buf;
        asnstruct->data = (void *)pgpasn_NewBMPString(ctx);
        if (asnstruct->data == NULL) {
            PGPASN_ERR(kPGPASNError_ErrOutOfMemory);
            return 0;
        }
        return (pgpasn_UnpkInPlaceBMPString(ctx, (PGPASN_BMPString *)(asnstruct->data),
                    buf, buflen,
                    PGPASN_ID_BMPString, erret));
        /*NOTREACHED*/
        break;

    /* ia5String */
    case PGPASN_ID_IA5String:
    case 0x20|PGPASN_ID_IA5String:
        asnstruct->CHOICE_field_type = *buf;
        asnstruct->data = (void *)pgpasn_NewIA5String(ctx);
        if (asnstruct->data == NULL) {
            PGPASN_ERR(kPGPASNError_ErrOutOfMemory);
            return 0;
        }
        return (pgpasn_UnpkInPlaceIA5String(ctx, (PGPASN_IA5String *)(asnstruct->data),
                    buf, buflen,
                    PGPASN_ID_IA5String, erret));
        /*NOTREACHED*/
        break;

    default:
        PGPASN_ERR(kPGPASNError_ErrChoiceBadType);
        return 0;

    } /* switch */

} /* pgpasn_UnpkInPlaceDirectoryString */

size_t pgpasn_UnpackDirectoryStringInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_DirectoryString **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_DirectoryString *local = NULL ;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

    local = pgpasn_NewDirectoryString(ctx) ; /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceDirectoryString(ctx, local, buf, buflen, tag, erret);
    if (*erret == kPGPASNError_ErrChoiceBadType) {
        *erret = 0;
        if (local != NULL) pgpasn_FreeDirectoryString(ctx, local);
        return 0;
    }
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeDirectoryString(ctx, local);
        return 0;
    }

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


/******************************************************************
 * Routines for DssParms
 ******************************************************************/

size_t pgpasn_SizeofDssParmsInternal(
    PGPASN_DssParms *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            pgpasn_SizeofINTEGERInternal(&asnstruct->p, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofINTEGERInternal(&asnstruct->q, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofINTEGERInternal(&asnstruct->g, PGPASN_TRUE, PGPASN_FALSE) ;

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;

} /* pgpasn_SizeofDssParmsInternal */

void pgpasn_DropInPlaceDssParms(
    PGPASN_CONTEXT *ctx,
    PGPASN_DssParms *f)
{
    if (ctx == NULL)
        return;

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

size_t pgpasn_PackDssParmsInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_DssParms *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofDssParms(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

  do {

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

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

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

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackDssParmsInternal */

size_t pgpasn_UnpkInPlaceDssParms(
    PGPASN_CONTEXT *ctx,
    PGPASN_DssParms *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;

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "DssParms" );

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

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

    PGPASN_TRACE_INCR_LEVEL;
  do {

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

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

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

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceDssParms */

size_t pgpasn_UnpackDssParmsInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_DssParms **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_DssParms *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewDssParms(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceDssParms(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeDssParms(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackDssParmsInternal */


/******************************************************************
 * Routines for DssSigValue
 ******************************************************************/

size_t pgpasn_SizeofDssSigValueInternal(
    PGPASN_DssSigValue *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            pgpasn_SizeofINTEGERInternal(&asnstruct->r, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofINTEGERInternal(&asnstruct->s, PGPASN_TRUE, PGPASN_FALSE) ;

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;

} /* pgpasn_SizeofDssSigValueInternal */

void pgpasn_DropInPlaceDssSigValue(
    PGPASN_CONTEXT *ctx,
    PGPASN_DssSigValue *f)
{
    if (ctx == NULL)
        return;

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

size_t pgpasn_PackDssSigValueInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_DssSigValue *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofDssSigValue(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

  do {

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

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

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackDssSigValueInternal */

size_t pgpasn_UnpkInPlaceDssSigValue(
    PGPASN_CONTEXT *ctx,
    PGPASN_DssSigValue *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;

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "DssSigValue" );

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

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

    PGPASN_TRACE_INCR_LEVEL;
  do {

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

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

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceDssSigValue */

size_t pgpasn_UnpackDssSigValueInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_DssSigValue **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_DssSigValue *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewDssSigValue(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceDssSigValue(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeDssSigValue(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackDssSigValueInternal */


/******************************************************************
 * Routines for ELGParms
 ******************************************************************/

size_t pgpasn_SizeofELGParmsInternal(
    PGPASN_ELGParms *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            pgpasn_SizeofINTEGERInternal(&asnstruct->p, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofINTEGERInternal(&asnstruct->g, PGPASN_TRUE, PGPASN_FALSE) ;

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;

} /* pgpasn_SizeofELGParmsInternal */

void pgpasn_DropInPlaceELGParms(
    PGPASN_CONTEXT *ctx,
    PGPASN_ELGParms *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    pgpasn_DropInPlaceINTEGER(ctx, &(f->p));
    pgpasn_DropInPlaceINTEGER(ctx, &(f->g));
} /* pgpasn_DropInPlaceELGParms */

size_t pgpasn_PackELGParmsInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_ELGParms *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofELGParms(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

  do {

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

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

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackELGParmsInternal */

size_t pgpasn_UnpkInPlaceELGParms(
    PGPASN_CONTEXT *ctx,
    PGPASN_ELGParms *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;

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "ELGParms" );

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

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

    PGPASN_TRACE_INCR_LEVEL;
  do {

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

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

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceELGParms */

size_t pgpasn_UnpackELGParmsInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_ELGParms **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_ELGParms *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewELGParms(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceELGParms(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeELGParms(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackELGParmsInternal */


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

size_t pgpasn_SizeofExtensionInternal(
    PGPASN_Extension *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            pgpasn_SizeofOBJECT_IDInternal(&asnstruct->extnID, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofBOOLEANInternal(asnstruct->critical, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofOCTET_STRINGInternal(&asnstruct->extnValue, PGPASN_TRUE, PGPASN_FALSE) ;

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;

} /* pgpasn_SizeofExtensionInternal */

void pgpasn_DropInPlaceExtension(
    PGPASN_CONTEXT *ctx,
    PGPASN_Extension *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    pgpasn_DropInPlaceOBJECT_ID(ctx, &(f->extnID));
    pgpasn_FreeBOOLEAN(ctx, f->critical);
    f->critical = NULL;
    pgpasn_DropInPlaceOCTET_STRING(ctx, &(f->extnValue));
} /* pgpasn_DropInPlaceExtension */

size_t pgpasn_PackExtensionInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_Extension *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofExtension(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

  do {

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

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

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

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackExtensionInternal */

size_t pgpasn_UnpkInPlaceExtension(
    PGPASN_CONTEXT *ctx,
    PGPASN_Extension *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;

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

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

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

    PGPASN_TRACE_INCR_LEVEL;
  do {

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

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

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

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceExtension */

size_t pgpasn_UnpackExtensionInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_Extension **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_Extension *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewExtension(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceExtension(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeExtension(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackExtensionInternal */


/******************************************************************
 * Routines for OtherName
 ******************************************************************/

size_t pgpasn_SizeofOtherNameInternal(
    PGPASN_OtherName *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            pgpasn_SizeofOBJECT_IDInternal(&asnstruct->type_id, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofANYInternal(&asnstruct->value, PGPASN_TRUE, PGPASN_TRUE) ;

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;

} /* pgpasn_SizeofOtherNameInternal */

void pgpasn_DropInPlaceOtherName(
    PGPASN_CONTEXT *ctx,
    PGPASN_OtherName *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    pgpasn_DropInPlaceOBJECT_ID(ctx, &(f->type_id));
    pgpasn_DropInPlaceANY(ctx, &(f->value));
} /* pgpasn_DropInPlaceOtherName */

size_t pgpasn_PackOtherNameInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_OtherName *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofOtherName(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

  do {

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

    /* field value of OtherName */
    bytesused += PGPASN_PutTag(buf+bytesused, 0xa0 | 0x00, pgpasn_SizeofANY(ctx, &(asnstruct->value ), PGPASN_TRUE));
    bytesused += pgpasn_PackANYInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->value), PGPASN_ID_ANY, erret);
    if (bytesused > datasize || *erret != 0)
        break;

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackOtherNameInternal */

size_t pgpasn_UnpkInPlaceOtherName(
    PGPASN_CONTEXT *ctx,
    PGPASN_OtherName *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;

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "OtherName" );

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

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

    PGPASN_TRACE_INCR_LEVEL;
  do {

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

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

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

        if ((int)taggeddatasize == -1 && used != 0) {
            PGPASN_TRACE_PRINT_TAG(0xa0|0x00, 0x00);
            PGPASN_TRACE_INCR_LEVEL;
            bytesused += pgpasn_UnpkInPlaceANY(ctx, &(asnstruct->value), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_ANY, erret);
            PGPASN_TRACE_DECR_LEVEL;
            if ( *(buf+bytesused) != 0x00 &&
                 *(buf+bytesused+1) != 0x00 ) {
                PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
                break;
            }
            bytesused += 2;
        }

        else if (taggeddatasize > 0 && used != 0) {
            taggedlocalsize = bytesused + taggeddatasize;
            PGPASN_TRACE_PRINT_TAG(0xa0|0x00, 0x00);
            PGPASN_TRACE_INCR_LEVEL;
            bytesused += pgpasn_UnpkInPlaceANY(ctx, &(asnstruct->value), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_ANY, erret);
            PGPASN_TRACE_DECR_LEVEL;
            if (bytesused != taggedlocalsize) {
                PGPASN_ERR(kPGPASNError_ErrUnpackTaggedLth);
                break;
            }
        }
    } /* for the local declaration block */
    if (bytesused > localsize || *erret != 0)
        break;

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceOtherName */

size_t pgpasn_UnpackOtherNameInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_OtherName **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_OtherName *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewOtherName(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceOtherName(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeOtherName(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackOtherNameInternal */


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

size_t pgpasn_SizeofRSAKeyInternal(
    PGPASN_RSAKey *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            pgpasn_SizeofINTEGERInternal(&asnstruct->modulus, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofINTEGERInternal(&asnstruct->exponent, PGPASN_TRUE, PGPASN_FALSE) ;

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;

} /* pgpasn_SizeofRSAKeyInternal */

void pgpasn_DropInPlaceRSAKey(
    PGPASN_CONTEXT *ctx,
    PGPASN_RSAKey *f)
{
    if (ctx == NULL)
        return;

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

size_t pgpasn_PackRSAKeyInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_RSAKey *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofRSAKey(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

  do {

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

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

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackRSAKeyInternal */

size_t pgpasn_UnpkInPlaceRSAKey(
    PGPASN_CONTEXT *ctx,
    PGPASN_RSAKey *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;

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

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

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

    PGPASN_TRACE_INCR_LEVEL;
  do {

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

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

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceRSAKey */

size_t pgpasn_UnpackRSAKeyInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_RSAKey **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_RSAKey *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewRSAKey(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceRSAKey(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeRSAKey(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackRSAKeyInternal */


/******************************************************************
 * Routines for RSAPrivateKey
 ******************************************************************/

size_t pgpasn_SizeofRSAPrivateKeyInternal(
    PGPASN_RSAPrivateKey *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            pgpasn_SizeofVersionInternal(&asnstruct->version, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofINTEGERInternal(&asnstruct->modulus, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofINTEGERInternal(&asnstruct->publicExponent, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofINTEGERInternal(&asnstruct->privateExponent, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofINTEGERInternal(&asnstruct->prime1, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofINTEGERInternal(&asnstruct->prime2, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofINTEGERInternal(&asnstruct->exponent1, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofINTEGERInternal(&asnstruct->exponent2, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofINTEGERInternal(&asnstruct->coefficient, PGPASN_TRUE, PGPASN_FALSE) ;

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;

} /* pgpasn_SizeofRSAPrivateKeyInternal */

void pgpasn_DropInPlaceRSAPrivateKey(
    PGPASN_CONTEXT *ctx,
    PGPASN_RSAPrivateKey *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    pgpasn_DropInPlaceVersion(ctx, &(f->version));
    pgpasn_DropInPlaceINTEGER(ctx, &(f->modulus));
    pgpasn_DropInPlaceINTEGER(ctx, &(f->publicExponent));
    pgpasn_DropInPlaceINTEGER(ctx, &(f->privateExponent));
    pgpasn_DropInPlaceINTEGER(ctx, &(f->prime1));
    pgpasn_DropInPlaceINTEGER(ctx, &(f->prime2));
    pgpasn_DropInPlaceINTEGER(ctx, &(f->exponent1));
    pgpasn_DropInPlaceINTEGER(ctx, &(f->exponent2));
    pgpasn_DropInPlaceINTEGER(ctx, &(f->coefficient));
} /* pgpasn_DropInPlaceRSAPrivateKey */

size_t pgpasn_PackRSAPrivateKeyInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_RSAPrivateKey *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofRSAPrivateKey(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

  do {

    /* field version of RSAPrivateKey */
    bytesused += pgpasn_PackVersionInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->version), PGPASN_ID_Version, erret);
    if (bytesused > datasize || *erret != 0)
        break;

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

    /* field publicExponent of RSAPrivateKey */
    bytesused += pgpasn_PackINTEGERInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->publicExponent), PGPASN_ID_INTEGER, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field privateExponent of RSAPrivateKey */
    bytesused += pgpasn_PackINTEGERInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->privateExponent), PGPASN_ID_INTEGER, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field prime1 of RSAPrivateKey */
    bytesused += pgpasn_PackINTEGERInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->prime1), PGPASN_ID_INTEGER, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field prime2 of RSAPrivateKey */
    bytesused += pgpasn_PackINTEGERInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->prime2), PGPASN_ID_INTEGER, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field exponent1 of RSAPrivateKey */
    bytesused += pgpasn_PackINTEGERInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->exponent1), PGPASN_ID_INTEGER, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field exponent2 of RSAPrivateKey */
    bytesused += pgpasn_PackINTEGERInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->exponent2), PGPASN_ID_INTEGER, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field coefficient of RSAPrivateKey */
    bytesused += pgpasn_PackINTEGERInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->coefficient), PGPASN_ID_INTEGER, erret);
    if (bytesused > datasize || *erret != 0)
        break;

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackRSAPrivateKeyInternal */

size_t pgpasn_UnpkInPlaceRSAPrivateKey(
    PGPASN_CONTEXT *ctx,
    PGPASN_RSAPrivateKey *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;

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "RSAPrivateKey" );

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

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

    PGPASN_TRACE_INCR_LEVEL;
  do {

    /* field version of RSAPrivateKey */
    bytesused += pgpasn_UnpkInPlaceVersion(ctx, &(asnstruct->version), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_Version, erret);
    if (bytesused > localsize || *erret != 0)
        break;

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

    /* field publicExponent of RSAPrivateKey */
    bytesused += pgpasn_UnpkInPlaceINTEGER(ctx, &(asnstruct->publicExponent), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_INTEGER, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field privateExponent of RSAPrivateKey */
    bytesused += pgpasn_UnpkInPlaceINTEGER(ctx, &(asnstruct->privateExponent), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_INTEGER, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field prime1 of RSAPrivateKey */
    bytesused += pgpasn_UnpkInPlaceINTEGER(ctx, &(asnstruct->prime1), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_INTEGER, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field prime2 of RSAPrivateKey */
    bytesused += pgpasn_UnpkInPlaceINTEGER(ctx, &(asnstruct->prime2), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_INTEGER, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field exponent1 of RSAPrivateKey */
    bytesused += pgpasn_UnpkInPlaceINTEGER(ctx, &(asnstruct->exponent1), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_INTEGER, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field exponent2 of RSAPrivateKey */
    bytesused += pgpasn_UnpkInPlaceINTEGER(ctx, &(asnstruct->exponent2), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_INTEGER, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field coefficient of RSAPrivateKey */
    bytesused += pgpasn_UnpkInPlaceINTEGER(ctx, &(asnstruct->coefficient), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_INTEGER, erret);
    if (bytesused > localsize || *erret != 0)
        break;

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceRSAPrivateKey */

size_t pgpasn_UnpackRSAPrivateKeyInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_RSAPrivateKey **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_RSAPrivateKey *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewRSAPrivateKey(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceRSAPrivateKey(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeRSAPrivateKey(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackRSAPrivateKeyInternal */


/******************************************************************
 * Routines for XIssuerAndSerialNumber
 ******************************************************************/

size_t pgpasn_SizeofXIssuerAndSerialNumberInternal(
    PGPASN_XIssuerAndSerialNumber *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            pgpasn_SizeofANYInternal(&asnstruct->issuer, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofCertificateSerialNumberInternal(&asnstruct->serialNumber, PGPASN_TRUE, PGPASN_FALSE) ;

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;

} /* pgpasn_SizeofXIssuerAndSerialNumberInternal */

void pgpasn_DropInPlaceXIssuerAndSerialNumber(
    PGPASN_CONTEXT *ctx,
    PGPASN_XIssuerAndSerialNumber *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    pgpasn_DropInPlaceANY(ctx, &(f->issuer));
    pgpasn_DropInPlaceCertificateSerialNumber(ctx, &(f->serialNumber));
} /* pgpasn_DropInPlaceXIssuerAndSerialNumber */

size_t pgpasn_PackXIssuerAndSerialNumberInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_XIssuerAndSerialNumber *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofXIssuerAndSerialNumber(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

  do {

    /* field issuer of XIssuerAndSerialNumber */
    bytesused += pgpasn_PackANYInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->issuer), PGPASN_ID_ANY, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field serialNumber of XIssuerAndSerialNumber */
    bytesused += pgpasn_PackCertificateSerialNumberInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->serialNumber), PGPASN_ID_CertificateSerialNumber, erret);
    if (bytesused > datasize || *erret != 0)
        break;

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackXIssuerAndSerialNumberInternal */

size_t pgpasn_UnpkInPlaceXIssuerAndSerialNumber(
    PGPASN_CONTEXT *ctx,
    PGPASN_XIssuerAndSerialNumber *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;

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "XIssuerAndSerialNumber" );

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

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

    PGPASN_TRACE_INCR_LEVEL;
  do {

    /* field issuer of XIssuerAndSerialNumber */
    bytesused += pgpasn_UnpkInPlaceANY(ctx, &(asnstruct->issuer), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_ANY, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field serialNumber of XIssuerAndSerialNumber */
    bytesused += pgpasn_UnpkInPlaceCertificateSerialNumber(ctx, &(asnstruct->serialNumber), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_CertificateSerialNumber, erret);
    if (bytesused > localsize || *erret != 0)
        break;

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceXIssuerAndSerialNumber */

size_t pgpasn_UnpackXIssuerAndSerialNumberInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_XIssuerAndSerialNumber **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_XIssuerAndSerialNumber *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewXIssuerAndSerialNumber(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceXIssuerAndSerialNumber(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeXIssuerAndSerialNumber(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackXIssuerAndSerialNumberInternal */


/******************************************************************
 * Routines for XXCertificate
 ******************************************************************/

size_t pgpasn_SizeofXXCertificateInternal(
    PGPASN_XXCertificate *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            pgpasn_SizeofANYInternal(&asnstruct->tbsCertificate, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofANYInternal(&asnstruct->signatureAlgorithm, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofANYInternal(&asnstruct->signature, PGPASN_TRUE, PGPASN_FALSE) ;

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;

} /* pgpasn_SizeofXXCertificateInternal */

void pgpasn_DropInPlaceXXCertificate(
    PGPASN_CONTEXT *ctx,
    PGPASN_XXCertificate *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    pgpasn_DropInPlaceANY(ctx, &(f->tbsCertificate));
    pgpasn_DropInPlaceANY(ctx, &(f->signatureAlgorithm));
    pgpasn_DropInPlaceANY(ctx, &(f->signature));
} /* pgpasn_DropInPlaceXXCertificate */

size_t pgpasn_PackXXCertificateInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_XXCertificate *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofXXCertificate(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

  do {

    /* field tbsCertificate of XXCertificate */
    bytesused += pgpasn_PackANYInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->tbsCertificate), PGPASN_ID_ANY, erret);
    if (bytesused > datasize || *erret != 0)
        break;

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

    /* field signature of XXCertificate */
    bytesused += pgpasn_PackANYInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->signature), PGPASN_ID_ANY, erret);
    if (bytesused > datasize || *erret != 0)
        break;

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackXXCertificateInternal */

size_t pgpasn_UnpkInPlaceXXCertificate(
    PGPASN_CONTEXT *ctx,
    PGPASN_XXCertificate *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;

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "XXCertificate" );

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

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

    PGPASN_TRACE_INCR_LEVEL;
  do {

    /* field tbsCertificate of XXCertificate */
    bytesused += pgpasn_UnpkInPlaceANY(ctx, &(asnstruct->tbsCertificate), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_ANY, erret);
    if (bytesused > localsize || *erret != 0)
        break;

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

    /* field signature of XXCertificate */
    bytesused += pgpasn_UnpkInPlaceANY(ctx, &(asnstruct->signature), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_ANY, erret);
    if (bytesused > localsize || *erret != 0)
        break;

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceXXCertificate */

size_t pgpasn_UnpackXXCertificateInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_XXCertificate **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_XXCertificate *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewXXCertificate(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceXXCertificate(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeXXCertificate(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackXXCertificateInternal */


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

size_t pgpasn_SizeofAttributeInternal(
    PGPASN_Attribute *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            pgpasn_SizeofAttributeTypeInternal(&asnstruct->type, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofAttributeValuesInternal(&asnstruct->values, PGPASN_TRUE, PGPASN_FALSE) ;

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;

} /* pgpasn_SizeofAttributeInternal */

void pgpasn_DropInPlaceAttribute(
    PGPASN_CONTEXT *ctx,
    PGPASN_Attribute *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    pgpasn_DropInPlaceAttributeType(ctx, &(f->type));
    pgpasn_DropInPlaceAttributeValues(ctx, &(f->values));
} /* pgpasn_DropInPlaceAttribute */

size_t pgpasn_PackAttributeInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_Attribute *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofAttribute(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

  do {

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

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

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackAttributeInternal */

size_t pgpasn_UnpkInPlaceAttribute(
    PGPASN_CONTEXT *ctx,
    PGPASN_Attribute *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;

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

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

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

    PGPASN_TRACE_INCR_LEVEL;
  do {

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

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

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceAttribute */

size_t pgpasn_UnpackAttributeInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_Attribute **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_Attribute *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewAttribute(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceAttribute(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeAttribute(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackAttributeInternal */


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

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

    if (asnstruct == NULL)
        return 0;

    lth = asnstruct->n ;
    if (lth > PGPASN_MAX_Extensions)
        lth = PGPASN_MAX_Extensions;	/* clamp it */
    for (i=0; i<lth; i++)
        body_size += pgpasn_SizeofExtensionInternal((asnstruct->elt)[i], PGPASN_TRUE, PGPASN_FALSE);

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;
} /* pgpasn_SizeofExtensionsInternal */

void pgpasn_DropInPlaceExtensions(
    PGPASN_CONTEXT *ctx,
    PGPASN_Extensions *f)
{
    long i, lth;

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

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

size_t pgpasn_PackExtensionsInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_Extensions *asnstruct,
    unsigned char tag,
    int *erret )
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;
    long numElem;
    int i;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

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

    /* lth of the block body */
    datasize = pgpasn_SizeofExtensions(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

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

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun);

    return bytesused;
} /* pgpasn_PackExtensionsInternal */

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

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE OF", "Extensions");

    if (erret == NULL) return 0;

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }
    bytesused ++; /* consume the tag byte */

    PGPASN_TRACE_INCR_LEVEL;

    bytesused += PGPASN_GetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
            asnstruct->n = -1 ; /* note where (-1 treated as 0) */
            PGPASN_TRACE_DECR_LEVEL;
            return 0;
        }
    }

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

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

        if (asnstruct->elt[i] == NULL)
            asnstruct->elt[i] = pgpasn_NewExtension(ctx);
        if (asnstruct->elt[i] == NULL) {
            PGPASN_ERR(kPGPASNError_ErrOutOfMemory);
            break;
        }
        asnstruct->n = i+1 ; /* note the new element */
        bytesused += pgpasn_UnpkInPlaceExtension(ctx, asnstruct->elt[i], buf+bytesused,
                            localsize-bytesused, PGPASN_ID_Extension, erret);
        if (*erret != 0)
            break;
    } /* for */

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceExtensions */

size_t pgpasn_UnpackExtensionsInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_Extensions **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_Extensions *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewExtensions(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceExtensions(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeExtensions(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackExtensionsInternal */


/******************************************************************
 * Routines for RelativeDistinguishedName
 ******************************************************************/

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

    if (asnstruct == NULL)
        return 0;

    lth = asnstruct->n;
    if (lth > PGPASN_MAX_RelativeDistinguishedName)
        lth = PGPASN_MAX_RelativeDistinguishedName;	/* clamp it */
    for (i=0;i<lth;i++)
        body_size += pgpasn_SizeofAttributeTypeAndValueInternal((asnstruct->elt)[i], PGPASN_TRUE, PGPASN_FALSE);

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;
} /* pgpasn_SizeofRelativeDistinguishedNameInternal */

void pgpasn_DropInPlaceRelativeDistinguishedName(
    PGPASN_CONTEXT *ctx,
    PGPASN_RelativeDistinguishedName *f)
{
    long i, lth;

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

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

size_t pgpasn_PackRelativeDistinguishedNameInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_RelativeDistinguishedName *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;
    PGPASN_VariableBlock temp[PGPASN_MAX_RelativeDistinguishedName];

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

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

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

    datasize = pgpasn_SizeofRelativeDistinguishedName(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

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

    else {

        /* calculate lengths and max */
        for (i=0; i<numElem; i++) {
            length = pgpasn_SizeofAttributeTypeAndValue(ctx, (asnstruct->elt)[i], PGPASN_TRUE);
            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 *)PGPASN_Alloc(ctx->memMgr, max);
            memset(temp[i].val, 0, max);
            (void) pgpasn_PackAttributeTypeAndValueInternal(ctx, temp[i].val,
                          max, (asnstruct->elt)[i],
                          PGPASN_ID_AttributeTypeAndValue, erret );
            if (*erret != 0) {
                for (j=0; j<i; j++)
                    PGPASN_Free(ctx->memMgr, temp[j].val);
                return 0;
            }
        }

        /* sort and look for duplicates */
        qsort(temp, numElem, sizeof(PGPASN_VariableBlock), PGPASN_CompareElems);
        for (i=0; i<(numElem-1); i++)
            if (memcmp(temp[i].val, temp[i+1].val, max) == 0) {
                PGPASN_ERR(kPGPASNError_ErrPackSETOFUnsortable);
                for (j=0; j<i; j++)
                    PGPASN_Free(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;
            PGPASN_Free(ctx->memMgr, temp[i].val);
        }
    }

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackRelativeDistinguishedNameInternal */

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

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x31, "SET OF", "RelativeDistinguishedName");

    if (erret == NULL) return 0;

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

    bytesused += PGPASN_GetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
            asnstruct->n = -1 ; /* note where (-1 treated as 0) */
            PGPASN_TRACE_DECR_LEVEL;
            return 0;
        }
    }

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

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

        if (asnstruct->elt[i] == NULL)
            asnstruct->elt[i] = pgpasn_NewAttributeTypeAndValue(ctx);
        if (asnstruct->elt[i] == NULL) {
            PGPASN_ERR(kPGPASNError_ErrOutOfMemory);
            break;
        }
        asnstruct->n = i+1 ; /* note the new element */
        bytesused += pgpasn_UnpkInPlaceAttributeTypeAndValue(ctx, asnstruct->elt[i],
                          buf+bytesused, localsize-bytesused,
                          PGPASN_ID_AttributeTypeAndValue, erret);
        if (*erret != 0)
            break;
    } /* for */

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceRelativeDistinguishedName */

size_t pgpasn_UnpackRelativeDistinguishedNameInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_RelativeDistinguishedName **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_RelativeDistinguishedName *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewRelativeDistinguishedName(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceRelativeDistinguishedName(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeRelativeDistinguishedName(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackRelativeDistinguishedNameInternal */


/******************************************************************
 * Routines for SubjectPublicKeyInfo
 ******************************************************************/

size_t pgpasn_SizeofSubjectPublicKeyInfoInternal(
    PGPASN_SubjectPublicKeyInfo *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            pgpasn_SizeofAlgorithmIdentifierInternal(&asnstruct->algorithm, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofBIT_STRINGInternal(&asnstruct->subjectPublicKey, PGPASN_TRUE, PGPASN_FALSE) ;

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;

} /* pgpasn_SizeofSubjectPublicKeyInfoInternal */

void pgpasn_DropInPlaceSubjectPublicKeyInfo(
    PGPASN_CONTEXT *ctx,
    PGPASN_SubjectPublicKeyInfo *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    pgpasn_DropInPlaceAlgorithmIdentifier(ctx, &(f->algorithm));
    pgpasn_DropInPlaceBIT_STRING(ctx, &(f->subjectPublicKey));
} /* pgpasn_DropInPlaceSubjectPublicKeyInfo */

size_t pgpasn_PackSubjectPublicKeyInfoInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_SubjectPublicKeyInfo *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofSubjectPublicKeyInfo(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

  do {

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

    /* field subjectPublicKey of SubjectPublicKeyInfo */
    bytesused += pgpasn_PackBIT_STRINGInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->subjectPublicKey), PGPASN_ID_BIT_STRING, erret);
    if (bytesused > datasize || *erret != 0)
        break;

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackSubjectPublicKeyInfoInternal */

size_t pgpasn_UnpkInPlaceSubjectPublicKeyInfo(
    PGPASN_CONTEXT *ctx,
    PGPASN_SubjectPublicKeyInfo *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;

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "SubjectPublicKeyInfo" );

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

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

    PGPASN_TRACE_INCR_LEVEL;
  do {

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

    /* field subjectPublicKey of SubjectPublicKeyInfo */
    bytesused += pgpasn_UnpkInPlaceBIT_STRING(ctx, &(asnstruct->subjectPublicKey), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_BIT_STRING, erret);
    if (bytesused > localsize || *erret != 0)
        break;

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceSubjectPublicKeyInfo */

size_t pgpasn_UnpackSubjectPublicKeyInfoInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_SubjectPublicKeyInfo **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_SubjectPublicKeyInfo *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewSubjectPublicKeyInfo(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceSubjectPublicKeyInfo(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeSubjectPublicKeyInfo(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackSubjectPublicKeyInfoInternal */


/******************************************************************
 * Routines for Validity
 ******************************************************************/

size_t pgpasn_SizeofValidityInternal(
    PGPASN_Validity *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            pgpasn_SizeofCertificateValidityDateInternal(&asnstruct->notBefore, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofCertificateValidityDateInternal(&asnstruct->notAfter, PGPASN_TRUE, PGPASN_FALSE) ;

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;

} /* pgpasn_SizeofValidityInternal */

void pgpasn_DropInPlaceValidity(
    PGPASN_CONTEXT *ctx,
    PGPASN_Validity *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    pgpasn_DropInPlaceCertificateValidityDate(ctx, &(f->notBefore));
    pgpasn_DropInPlaceCertificateValidityDate(ctx, &(f->notAfter));
} /* pgpasn_DropInPlaceValidity */

size_t pgpasn_PackValidityInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_Validity *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofValidity(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

  do {

    /* field notBefore of Validity */
    bytesused += pgpasn_PackCertificateValidityDateInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->notBefore), PGPASN_ID_CertificateValidityDate, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field notAfter of Validity */
    bytesused += pgpasn_PackCertificateValidityDateInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->notAfter), PGPASN_ID_CertificateValidityDate, erret);
    if (bytesused > datasize || *erret != 0)
        break;

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackValidityInternal */

size_t pgpasn_UnpkInPlaceValidity(
    PGPASN_CONTEXT *ctx,
    PGPASN_Validity *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;

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "Validity" );

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

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

    PGPASN_TRACE_INCR_LEVEL;
  do {

    /* field notBefore of Validity */
    bytesused += pgpasn_UnpkInPlaceCertificateValidityDate(ctx, &(asnstruct->notBefore), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_CertificateValidityDate, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field notAfter of Validity */
    bytesused += pgpasn_UnpkInPlaceCertificateValidityDate(ctx, &(asnstruct->notAfter), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_CertificateValidityDate, erret);
    if (bytesused > localsize || *erret != 0)
        break;

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceValidity */

size_t pgpasn_UnpackValidityInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_Validity **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_Validity *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewValidity(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceValidity(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeValidity(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackValidityInternal */


/******************************************************************
 * Routines for XCertificate
 ******************************************************************/

size_t pgpasn_SizeofXCertificateInternal(
    PGPASN_XCertificate *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            pgpasn_SizeofANYInternal(&asnstruct->tbsCertificate, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofAlgorithmIdentifierInternal(&asnstruct->signatureAlgorithm, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofBIT_STRINGInternal(&asnstruct->signature, PGPASN_TRUE, PGPASN_FALSE) ;

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;

} /* pgpasn_SizeofXCertificateInternal */

void pgpasn_DropInPlaceXCertificate(
    PGPASN_CONTEXT *ctx,
    PGPASN_XCertificate *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    pgpasn_DropInPlaceANY(ctx, &(f->tbsCertificate));
    pgpasn_DropInPlaceAlgorithmIdentifier(ctx, &(f->signatureAlgorithm));
    pgpasn_DropInPlaceBIT_STRING(ctx, &(f->signature));
} /* pgpasn_DropInPlaceXCertificate */

size_t pgpasn_PackXCertificateInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_XCertificate *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofXCertificate(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

  do {

    /* field tbsCertificate of XCertificate */
    bytesused += pgpasn_PackANYInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->tbsCertificate), PGPASN_ID_ANY, erret);
    if (bytesused > datasize || *erret != 0)
        break;

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

    /* field signature of XCertificate */
    bytesused += pgpasn_PackBIT_STRINGInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->signature), PGPASN_ID_BIT_STRING, erret);
    if (bytesused > datasize || *erret != 0)
        break;

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackXCertificateInternal */

size_t pgpasn_UnpkInPlaceXCertificate(
    PGPASN_CONTEXT *ctx,
    PGPASN_XCertificate *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;

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "XCertificate" );

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

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

    PGPASN_TRACE_INCR_LEVEL;
  do {

    /* field tbsCertificate of XCertificate */
    bytesused += pgpasn_UnpkInPlaceANY(ctx, &(asnstruct->tbsCertificate), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_ANY, erret);
    if (bytesused > localsize || *erret != 0)
        break;

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

    /* field signature of XCertificate */
    bytesused += pgpasn_UnpkInPlaceBIT_STRING(ctx, &(asnstruct->signature), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_BIT_STRING, erret);
    if (bytesused > localsize || *erret != 0)
        break;

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceXCertificate */

size_t pgpasn_UnpackXCertificateInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_XCertificate **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_XCertificate *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewXCertificate(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceXCertificate(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeXCertificate(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackXCertificateInternal */


/******************************************************************
 * Routines for Attributes
 ******************************************************************/

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

    if (asnstruct == NULL)
        return 0;

    lth = asnstruct->n;
    if (lth > PGPASN_MAX_Attributes)
        lth = PGPASN_MAX_Attributes;	/* clamp it */
    for (i=0;i<lth;i++)
        body_size += pgpasn_SizeofAttributeInternal((asnstruct->elt)[i], PGPASN_TRUE, PGPASN_FALSE);

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;
} /* pgpasn_SizeofAttributesInternal */

void pgpasn_DropInPlaceAttributes(
    PGPASN_CONTEXT *ctx,
    PGPASN_Attributes *f)
{
    long i, lth;

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

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

size_t pgpasn_PackAttributesInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_Attributes *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;
    PGPASN_VariableBlock temp[PGPASN_MAX_Attributes];

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

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

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

    datasize = pgpasn_SizeofAttributes(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

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

    else {

        /* calculate lengths and max */
        for (i=0; i<numElem; i++) {
            length = pgpasn_SizeofAttribute(ctx, (asnstruct->elt)[i], PGPASN_TRUE);
            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 *)PGPASN_Alloc(ctx->memMgr, max);
            memset(temp[i].val, 0, max);
            (void) pgpasn_PackAttributeInternal(ctx, temp[i].val,
                          max, (asnstruct->elt)[i],
                          PGPASN_ID_Attribute, erret );
            if (*erret != 0) {
                for (j=0; j<i; j++)
                    PGPASN_Free(ctx->memMgr, temp[j].val);
                return 0;
            }
        }

        /* sort and look for duplicates */
        qsort(temp, numElem, sizeof(PGPASN_VariableBlock), PGPASN_CompareElems);
        for (i=0; i<(numElem-1); i++)
            if (memcmp(temp[i].val, temp[i+1].val, max) == 0) {
                PGPASN_ERR(kPGPASNError_ErrPackSETOFUnsortable);
                for (j=0; j<i; j++)
                    PGPASN_Free(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;
            PGPASN_Free(ctx->memMgr, temp[i].val);
        }
    }

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackAttributesInternal */

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

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x31, "SET OF", "Attributes");

    if (erret == NULL) return 0;

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

    bytesused += PGPASN_GetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
            asnstruct->n = -1 ; /* note where (-1 treated as 0) */
            PGPASN_TRACE_DECR_LEVEL;
            return 0;
        }
    }

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

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

        if (asnstruct->elt[i] == NULL)
            asnstruct->elt[i] = pgpasn_NewAttribute(ctx);
        if (asnstruct->elt[i] == NULL) {
            PGPASN_ERR(kPGPASNError_ErrOutOfMemory);
            break;
        }
        asnstruct->n = i+1 ; /* note the new element */
        bytesused += pgpasn_UnpkInPlaceAttribute(ctx, asnstruct->elt[i],
                          buf+bytesused, localsize-bytesused,
                          PGPASN_ID_Attribute, erret);
        if (*erret != 0)
            break;
    } /* for */

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceAttributes */

size_t pgpasn_UnpackAttributesInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_Attributes **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_Attributes *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewAttributes(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceAttributes(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeAttributes(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackAttributesInternal */


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

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

    if (asnstruct == NULL)
        return 0;

    lth = asnstruct->n;
    if (lth > PGPASN_MAX_DigestAlgorithmIdentifiers)
        lth = PGPASN_MAX_DigestAlgorithmIdentifiers;	/* clamp it */
    for (i=0;i<lth;i++)
        body_size += pgpasn_SizeofDigestAlgorithmIdentifierInternal((asnstruct->elt)[i], PGPASN_TRUE, PGPASN_FALSE);

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;
} /* pgpasn_SizeofDigestAlgorithmIdentifiersInternal */

void pgpasn_DropInPlaceDigestAlgorithmIdentifiers(
    PGPASN_CONTEXT *ctx,
    PGPASN_DigestAlgorithmIdentifiers *f)
{
    long i, lth;

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

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

size_t pgpasn_PackDigestAlgorithmIdentifiersInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_DigestAlgorithmIdentifiers *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;
    PGPASN_VariableBlock temp[PGPASN_MAX_DigestAlgorithmIdentifiers];

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

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

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

    datasize = pgpasn_SizeofDigestAlgorithmIdentifiers(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

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

    else {

        /* calculate lengths and max */
        for (i=0; i<numElem; i++) {
            length = pgpasn_SizeofDigestAlgorithmIdentifier(ctx, (asnstruct->elt)[i], PGPASN_TRUE);
            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 *)PGPASN_Alloc(ctx->memMgr, max);
            memset(temp[i].val, 0, max);
            (void) pgpasn_PackDigestAlgorithmIdentifierInternal(ctx, temp[i].val,
                          max, (asnstruct->elt)[i],
                          PGPASN_ID_DigestAlgorithmIdentifier, erret );
            if (*erret != 0) {
                for (j=0; j<i; j++)
                    PGPASN_Free(ctx->memMgr, temp[j].val);
                return 0;
            }
        }

        /* sort and look for duplicates */
        qsort(temp, numElem, sizeof(PGPASN_VariableBlock), PGPASN_CompareElems);
        for (i=0; i<(numElem-1); i++)
            if (memcmp(temp[i].val, temp[i+1].val, max) == 0) {
                PGPASN_ERR(kPGPASNError_ErrPackSETOFUnsortable);
                for (j=0; j<i; j++)
                    PGPASN_Free(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;
            PGPASN_Free(ctx->memMgr, temp[i].val);
        }
    }

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackDigestAlgorithmIdentifiersInternal */

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

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x31, "SET OF", "DigestAlgorithmIdentifiers");

    if (erret == NULL) return 0;

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

    bytesused += PGPASN_GetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
            asnstruct->n = -1 ; /* note where (-1 treated as 0) */
            PGPASN_TRACE_DECR_LEVEL;
            return 0;
        }
    }

    for (i=0; (i < PGPASN_MAX_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] = pgpasn_NewDigestAlgorithmIdentifier(ctx);
        if (asnstruct->elt[i] == NULL) {
            PGPASN_ERR(kPGPASNError_ErrOutOfMemory);
            break;
        }
        asnstruct->n = i+1 ; /* note the new element */
        bytesused += pgpasn_UnpkInPlaceDigestAlgorithmIdentifier(ctx, asnstruct->elt[i],
                          buf+bytesused, localsize-bytesused,
                          PGPASN_ID_DigestAlgorithmIdentifier, erret);
        if (*erret != 0)
            break;
    } /* for */

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceDigestAlgorithmIdentifiers */

size_t pgpasn_UnpackDigestAlgorithmIdentifiersInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_DigestAlgorithmIdentifiers **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_DigestAlgorithmIdentifiers *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewDigestAlgorithmIdentifiers(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceDigestAlgorithmIdentifiers(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeDigestAlgorithmIdentifiers(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackDigestAlgorithmIdentifiersInternal */


/******************************************************************
 * Routines for PGPExtension
 ******************************************************************/

size_t pgpasn_SizeofPGPExtensionInternal(
    PGPASN_PGPExtension *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            pgpasn_SizeofVersionInternal(asnstruct->version, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofTimeInternal(&asnstruct->keyCreation, PGPASN_TRUE, PGPASN_FALSE) ;

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;

} /* pgpasn_SizeofPGPExtensionInternal */

void pgpasn_DropInPlacePGPExtension(
    PGPASN_CONTEXT *ctx,
    PGPASN_PGPExtension *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    pgpasn_FreeVersion(ctx, f->version);
    f->version = NULL;
    pgpasn_DropInPlaceTime(ctx, &(f->keyCreation));
} /* pgpasn_DropInPlacePGPExtension */

size_t pgpasn_PackPGPExtensionInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_PGPExtension *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofPGPExtension(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

  do {

    /* field version of PGPExtension */
    if (asnstruct->version != NULL) { /* optional */
        bytesused += pgpasn_PackVersionInternal(ctx, buf+bytesused, buflen-bytesused,
                          asnstruct->version, PGPASN_ID_Version, erret );
        if (bytesused > datasize || *erret != 0)
            break;
    }

    /* field keyCreation of PGPExtension */
    bytesused += pgpasn_PackTimeInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->keyCreation), PGPASN_ID_Time, erret);
    if (bytesused > datasize || *erret != 0)
        break;

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackPGPExtensionInternal */

size_t pgpasn_UnpkInPlacePGPExtension(
    PGPASN_CONTEXT *ctx,
    PGPASN_PGPExtension *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;

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "PGPExtension" );

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

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

    PGPASN_TRACE_INCR_LEVEL;
  do {

    /* field version of PGPExtension */
    if (asnstruct->version != NULL)
        pgpasn_FreeVersion(ctx, asnstruct->version);
    bytesused += pgpasn_UnpackVersionInternal(ctx, &(asnstruct->version),
                    buf+bytesused, localsize-bytesused, PGPASN_ID_Version, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field keyCreation of PGPExtension */
    bytesused += pgpasn_UnpkInPlaceTime(ctx, &(asnstruct->keyCreation), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_Time, erret);
    if (bytesused > localsize || *erret != 0)
        break;

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlacePGPExtension */

size_t pgpasn_UnpackPGPExtensionInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_PGPExtension **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_PGPExtension *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewPGPExtension(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlacePGPExtension(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreePGPExtension(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackPGPExtensionInternal */


/******************************************************************
 * Routines for RDNSequence
 ******************************************************************/

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

    if (asnstruct == NULL)
        return 0;

    lth = asnstruct->n ;
    if (lth > PGPASN_MAX_RDNSequence)
        lth = PGPASN_MAX_RDNSequence;	/* clamp it */
    for (i=0; i<lth; i++)
        body_size += pgpasn_SizeofRelativeDistinguishedNameInternal((asnstruct->elt)[i], PGPASN_TRUE, PGPASN_FALSE);

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;
} /* pgpasn_SizeofRDNSequenceInternal */

void pgpasn_DropInPlaceRDNSequence(
    PGPASN_CONTEXT *ctx,
    PGPASN_RDNSequence *f)
{
    long i, lth;

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

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

size_t pgpasn_PackRDNSequenceInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_RDNSequence *asnstruct,
    unsigned char tag,
    int *erret )
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;
    long numElem;
    int i;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

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

    /* lth of the block body */
    datasize = pgpasn_SizeofRDNSequence(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

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

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun);

    return bytesused;
} /* pgpasn_PackRDNSequenceInternal */

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

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE OF", "RDNSequence");

    if (erret == NULL) return 0;

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }
    bytesused ++; /* consume the tag byte */

    PGPASN_TRACE_INCR_LEVEL;

    bytesused += PGPASN_GetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
            asnstruct->n = -1 ; /* note where (-1 treated as 0) */
            PGPASN_TRACE_DECR_LEVEL;
            return 0;
        }
    }

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

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

        if (asnstruct->elt[i] == NULL)
            asnstruct->elt[i] = pgpasn_NewRelativeDistinguishedName(ctx);
        if (asnstruct->elt[i] == NULL) {
            PGPASN_ERR(kPGPASNError_ErrOutOfMemory);
            break;
        }
        asnstruct->n = i+1 ; /* note the new element */
        bytesused += pgpasn_UnpkInPlaceRelativeDistinguishedName(ctx, asnstruct->elt[i], buf+bytesused,
                            localsize-bytesused, PGPASN_ID_RelativeDistinguishedName, erret);
        if (*erret != 0)
            break;
    } /* for */

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceRDNSequence */

size_t pgpasn_UnpackRDNSequenceInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_RDNSequence **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_RDNSequence *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewRDNSequence(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceRDNSequence(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeRDNSequence(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackRDNSequenceInternal */


/******************************************************************
 * Routines for RevokedCertificate
 ******************************************************************/

size_t pgpasn_SizeofRevokedCertificateInternal(
    PGPASN_RevokedCertificate *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            pgpasn_SizeofCertificateSerialNumberInternal(&asnstruct->userCertificate, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofTimeInternal(&asnstruct->revocationDate, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofExtensionsInternal(asnstruct->crlEntryExtensions, PGPASN_TRUE, PGPASN_FALSE) ;

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;

} /* pgpasn_SizeofRevokedCertificateInternal */

void pgpasn_DropInPlaceRevokedCertificate(
    PGPASN_CONTEXT *ctx,
    PGPASN_RevokedCertificate *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    pgpasn_DropInPlaceCertificateSerialNumber(ctx, &(f->userCertificate));
    pgpasn_DropInPlaceTime(ctx, &(f->revocationDate));
    pgpasn_FreeExtensions(ctx, f->crlEntryExtensions);
    f->crlEntryExtensions = NULL;
} /* pgpasn_DropInPlaceRevokedCertificate */

size_t pgpasn_PackRevokedCertificateInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_RevokedCertificate *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofRevokedCertificate(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

  do {

    /* field userCertificate of RevokedCertificate */
    bytesused += pgpasn_PackCertificateSerialNumberInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->userCertificate), PGPASN_ID_CertificateSerialNumber, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field revocationDate of RevokedCertificate */
    bytesused += pgpasn_PackTimeInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->revocationDate), PGPASN_ID_Time, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field crlEntryExtensions of RevokedCertificate */
    if (asnstruct->crlEntryExtensions != NULL) { /* optional */
        bytesused += pgpasn_PackExtensionsInternal(ctx, buf+bytesused, buflen-bytesused,
                          asnstruct->crlEntryExtensions, PGPASN_ID_Extensions, erret );
        if (bytesused > datasize || *erret != 0)
            break;
    }

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackRevokedCertificateInternal */

size_t pgpasn_UnpkInPlaceRevokedCertificate(
    PGPASN_CONTEXT *ctx,
    PGPASN_RevokedCertificate *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;

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "RevokedCertificate" );

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

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

    PGPASN_TRACE_INCR_LEVEL;
  do {

    /* field userCertificate of RevokedCertificate */
    bytesused += pgpasn_UnpkInPlaceCertificateSerialNumber(ctx, &(asnstruct->userCertificate), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_CertificateSerialNumber, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field revocationDate of RevokedCertificate */
    bytesused += pgpasn_UnpkInPlaceTime(ctx, &(asnstruct->revocationDate), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_Time, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field crlEntryExtensions of RevokedCertificate */
    if (!indef && bytesused >= localsize) {
        PGPASN_TRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PGPASN_TRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->crlEntryExtensions != NULL)
        pgpasn_FreeExtensions(ctx, asnstruct->crlEntryExtensions);
    bytesused += pgpasn_UnpackExtensionsInternal(ctx, &(asnstruct->crlEntryExtensions),
                    buf+bytesused, localsize-bytesused, PGPASN_ID_Extensions, erret);
    if (bytesused > localsize || *erret != 0)
        break;

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceRevokedCertificate */

size_t pgpasn_UnpackRevokedCertificateInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_RevokedCertificate **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_RevokedCertificate *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewRevokedCertificate(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceRevokedCertificate(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeRevokedCertificate(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackRevokedCertificateInternal */


/******************************************************************
 * Routines for XTBSCertificate
 ******************************************************************/

size_t pgpasn_SizeofXTBSCertificateInternal(
    PGPASN_XTBSCertificate *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            pgpasn_SizeofVersionInternal(asnstruct->version, PGPASN_TRUE, PGPASN_TRUE)
          + pgpasn_SizeofCertificateSerialNumberInternal(&asnstruct->serialNumber, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofAlgorithmIdentifierInternal(&asnstruct->signature, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofANYInternal(&asnstruct->issuer, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofANYInternal(&asnstruct->validity, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofANYInternal(&asnstruct->subject, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofANYInternal(&asnstruct->subjectPublicKeyInfo, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofUniqueIdentifierInternal(asnstruct->issuerUniqueID, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofUniqueIdentifierInternal(asnstruct->subjectUniqueID, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofExtensionsInternal(asnstruct->extensions, PGPASN_TRUE, PGPASN_TRUE) ;

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;

} /* pgpasn_SizeofXTBSCertificateInternal */

void pgpasn_DropInPlaceXTBSCertificate(
    PGPASN_CONTEXT *ctx,
    PGPASN_XTBSCertificate *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    pgpasn_FreeVersion(ctx, f->version);
    f->version = NULL;
    pgpasn_DropInPlaceCertificateSerialNumber(ctx, &(f->serialNumber));
    pgpasn_DropInPlaceAlgorithmIdentifier(ctx, &(f->signature));
    pgpasn_DropInPlaceANY(ctx, &(f->issuer));
    pgpasn_DropInPlaceANY(ctx, &(f->validity));
    pgpasn_DropInPlaceANY(ctx, &(f->subject));
    pgpasn_DropInPlaceANY(ctx, &(f->subjectPublicKeyInfo));
    pgpasn_FreeUniqueIdentifier(ctx, f->issuerUniqueID);
    f->issuerUniqueID = NULL;
    pgpasn_FreeUniqueIdentifier(ctx, f->subjectUniqueID);
    f->subjectUniqueID = NULL;
    pgpasn_FreeExtensions(ctx, f->extensions);
    f->extensions = NULL;
} /* pgpasn_DropInPlaceXTBSCertificate */

size_t pgpasn_PackXTBSCertificateInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_XTBSCertificate *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofXTBSCertificate(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

  do {

    /* field version of XTBSCertificate */
    if (asnstruct->version != NULL) { /* optional */
        bytesused += PGPASN_PutTag(buf+bytesused, 0xa0 | 0x00, pgpasn_SizeofVersion(ctx, asnstruct->version, PGPASN_TRUE));
        bytesused += pgpasn_PackVersionInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->version, PGPASN_ID_Version, erret) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

    /* field serialNumber of XTBSCertificate */
    bytesused += pgpasn_PackCertificateSerialNumberInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->serialNumber), PGPASN_ID_CertificateSerialNumber, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field signature of XTBSCertificate */
    bytesused += pgpasn_PackAlgorithmIdentifierInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->signature), PGPASN_ID_AlgorithmIdentifier, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field issuer of XTBSCertificate */
    bytesused += pgpasn_PackANYInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->issuer), PGPASN_ID_ANY, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field validity of XTBSCertificate */
    bytesused += pgpasn_PackANYInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->validity), PGPASN_ID_ANY, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field subject of XTBSCertificate */
    bytesused += pgpasn_PackANYInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->subject), PGPASN_ID_ANY, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field subjectPublicKeyInfo of XTBSCertificate */
    bytesused += pgpasn_PackANYInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->subjectPublicKeyInfo), PGPASN_ID_ANY, erret);
    if (bytesused > datasize || *erret != 0)
        break;

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

    /* field subjectUniqueID of XTBSCertificate */
    if (asnstruct->subjectUniqueID != NULL) { /* optional */
        bytesused += pgpasn_PackUniqueIdentifierInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->subjectUniqueID, 0x80 | 0x02, erret ) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

    /* field extensions of XTBSCertificate */
    if (asnstruct->extensions != NULL) { /* optional */
        bytesused += PGPASN_PutTag(buf+bytesused, 0xa0 | 0x03, pgpasn_SizeofExtensions(ctx, asnstruct->extensions, PGPASN_TRUE));
        bytesused += pgpasn_PackExtensionsInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->extensions, PGPASN_ID_Extensions, erret) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackXTBSCertificateInternal */

size_t pgpasn_UnpkInPlaceXTBSCertificate(
    PGPASN_CONTEXT *ctx,
    PGPASN_XTBSCertificate *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;

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "XTBSCertificate" );

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

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

    PGPASN_TRACE_INCR_LEVEL;
  do {

    /* field version of XTBSCertificate */
    { /* local declaration block*/
        size_t taggeddatasize;
        size_t taggedlocalsize;
        size_t used;

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

        if ((int)taggeddatasize == -1 && used != 0) {
            PGPASN_TRACE_PRINT_TAG(0xa0|0x00, 0x00);
            PGPASN_TRACE_INCR_LEVEL;
            if (asnstruct->version != NULL)
                pgpasn_FreeVersion(ctx, asnstruct->version);
            bytesused += pgpasn_UnpackVersionInternal(ctx, &(asnstruct->version),
                    buf+bytesused, localsize-bytesused, PGPASN_ID_Version, erret);
            PGPASN_TRACE_DECR_LEVEL;
            if ( *(buf+bytesused) != 0x00 &&
                 *(buf+bytesused+1) != 0x00 ) {
                PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
                break;
            }
            bytesused += 2;
        }

        else if (taggeddatasize > 0 && used != 0) {
            taggedlocalsize = bytesused + taggeddatasize;
            PGPASN_TRACE_PRINT_TAG(0xa0|0x00, 0x00);
            PGPASN_TRACE_INCR_LEVEL;
            if (asnstruct->version != NULL)
                pgpasn_FreeVersion(ctx, asnstruct->version);
            bytesused += pgpasn_UnpackVersionInternal(ctx, &(asnstruct->version),
                       buf+bytesused, localsize-bytesused, PGPASN_ID_Version, erret);
            PGPASN_TRACE_DECR_LEVEL;
            if (bytesused != taggedlocalsize) {
                PGPASN_ERR(kPGPASNError_ErrUnpackTaggedLth);
                break;
            }
        }
    } /* for the local declaration block */
    if (bytesused > localsize || *erret != 0)
        break;

    /* field serialNumber of XTBSCertificate */
    bytesused += pgpasn_UnpkInPlaceCertificateSerialNumber(ctx, &(asnstruct->serialNumber), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_CertificateSerialNumber, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field signature of XTBSCertificate */
    bytesused += pgpasn_UnpkInPlaceAlgorithmIdentifier(ctx, &(asnstruct->signature), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_AlgorithmIdentifier, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field issuer of XTBSCertificate */
    bytesused += pgpasn_UnpkInPlaceANY(ctx, &(asnstruct->issuer), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_ANY, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field validity of XTBSCertificate */
    bytesused += pgpasn_UnpkInPlaceANY(ctx, &(asnstruct->validity), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_ANY, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field subject of XTBSCertificate */
    bytesused += pgpasn_UnpkInPlaceANY(ctx, &(asnstruct->subject), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_ANY, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field subjectPublicKeyInfo of XTBSCertificate */
    bytesused += pgpasn_UnpkInPlaceANY(ctx, &(asnstruct->subjectPublicKeyInfo), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_ANY, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field issuerUniqueID of XTBSCertificate */
    if (!indef && bytesused >= localsize) {
        PGPASN_TRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PGPASN_TRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->issuerUniqueID != NULL)
        pgpasn_FreeUniqueIdentifier(ctx, asnstruct->issuerUniqueID);
    bytesused += pgpasn_UnpackUniqueIdentifierInternal(ctx, &(asnstruct->issuerUniqueID),
                 buf+bytesused, localsize-bytesused,
                 0x80 | 0x01, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field subjectUniqueID of XTBSCertificate */
    if (!indef && bytesused >= localsize) {
        PGPASN_TRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PGPASN_TRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->subjectUniqueID != NULL)
        pgpasn_FreeUniqueIdentifier(ctx, asnstruct->subjectUniqueID);
    bytesused += pgpasn_UnpackUniqueIdentifierInternal(ctx, &(asnstruct->subjectUniqueID),
                 buf+bytesused, localsize-bytesused,
                 0x80 | 0x02, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field extensions of XTBSCertificate */
    if (!indef && bytesused >= localsize) {
        PGPASN_TRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PGPASN_TRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    { /* local declaration block*/
        size_t taggeddatasize;
        size_t taggedlocalsize;
        size_t used;

        used = PGPASN_TakeTag(buf+bytesused, 0xa0 | 0x03,
                          &taggeddatasize);
        bytesused += used;

        if ((int)taggeddatasize == -1 && used != 0) {
            PGPASN_TRACE_PRINT_TAG(0xa0|0x03, 0x03);
            PGPASN_TRACE_INCR_LEVEL;
            if (asnstruct->extensions != NULL)
                pgpasn_FreeExtensions(ctx, asnstruct->extensions);
            bytesused += pgpasn_UnpackExtensionsInternal(ctx, &(asnstruct->extensions),
                    buf+bytesused, localsize-bytesused, PGPASN_ID_Extensions, erret);
            PGPASN_TRACE_DECR_LEVEL;
            if ( *(buf+bytesused) != 0x00 &&
                 *(buf+bytesused+1) != 0x00 ) {
                PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
                break;
            }
            bytesused += 2;
        }

        else if (taggeddatasize > 0 && used != 0) {
            taggedlocalsize = bytesused + taggeddatasize;
            PGPASN_TRACE_PRINT_TAG(0xa0|0x03, 0x03);
            PGPASN_TRACE_INCR_LEVEL;
            if (asnstruct->extensions != NULL)
                pgpasn_FreeExtensions(ctx, asnstruct->extensions);
            bytesused += pgpasn_UnpackExtensionsInternal(ctx, &(asnstruct->extensions),
                       buf+bytesused, localsize-bytesused, PGPASN_ID_Extensions, erret);
            PGPASN_TRACE_DECR_LEVEL;
            if (bytesused != taggedlocalsize) {
                PGPASN_ERR(kPGPASNError_ErrUnpackTaggedLth);
                break;
            }
        }
    } /* for the local declaration block */
    if (bytesused > localsize || *erret != 0)
        break;

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceXTBSCertificate */

size_t pgpasn_UnpackXTBSCertificateInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_XTBSCertificate **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_XTBSCertificate *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewXTBSCertificate(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceXTBSCertificate(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeXTBSCertificate(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackXTBSCertificateInternal */


/******************************************************************
 * Routines for Name
 ******************************************************************/

size_t pgpasn_SizeofNameInternal(
    PGPASN_Name *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    switch (asnstruct->CHOICE_field_type) {
      case PGPASN_ID_RDNSequence:
      case 0x20|PGPASN_ID_RDNSequence:
        body_size = pgpasn_SizeofRDNSequenceInternal((PGPASN_RDNSequence *)(asnstruct->data), outerSizeFlag, expTaggedFlag);
        break;

      default:
        break;

    } /* switch */

    return (body_size);
} /* pgpasn_SizeofNameInternal */

void pgpasn_DropInPlaceName(
    PGPASN_CONTEXT *ctx,
    PGPASN_Name *f)
{
    if (ctx == NULL) return;
    if (f == NULL) return;

    switch(f->CHOICE_field_type) {

    case PGPASN_ID_RDNSequence:
    case 0x20|PGPASN_ID_RDNSequence:
        pgpasn_FreeRDNSequence(ctx, (PGPASN_RDNSequence *)( f->data ));
        break;
    default:
        break;
    } /* switch */

} /* pgpasn_DropInPlaceName */

size_t pgpasn_PackNameInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_Name *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofName(ctx, asnstruct, PGPASN_TRUE);
    if (datasize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

    case PGPASN_ID_RDNSequence:
        bytesused += pgpasn_PackRDNSequenceInternal(ctx, buf+bytesused, buflen-bytesused,
                     (PGPASN_RDNSequence *)(asnstruct->data),
                     PGPASN_ID_RDNSequence,
                     erret);
        break;

    default:
        PGPASN_ERR( kPGPASNError_ErrChoiceBadType );
        break;
    } /* switch */

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

  return bytesused;
} /* pgpasn_PackNameInternal */

size_t pgpasn_UnpkInPlaceName(
     PGPASN_CONTEXT *ctx,
     PGPASN_Name *asnstruct,/* output block */
     const unsigned char *buf,
     size_t buflen,
     unsigned char tag,
     int *erret)
{
    (void)tag; /* unused */


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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        return 0;
    }

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

    switch (*buf) {

    /* rdnSequence */
    case PGPASN_ID_RDNSequence:
    case 0x20|PGPASN_ID_RDNSequence:
        asnstruct->CHOICE_field_type = *buf;
        asnstruct->data = (void *)pgpasn_NewRDNSequence(ctx);
        if (asnstruct->data == NULL) {
            PGPASN_ERR(kPGPASNError_ErrOutOfMemory);
            return 0;
        }
        return (pgpasn_UnpkInPlaceRDNSequence(ctx, (PGPASN_RDNSequence *)(asnstruct->data),
                    buf, buflen,
                    PGPASN_ID_RDNSequence, erret));
        /*NOTREACHED*/
        break;

    default:
        PGPASN_ERR(kPGPASNError_ErrChoiceBadType);
        return 0;

    } /* switch */

} /* pgpasn_UnpkInPlaceName */

size_t pgpasn_UnpackNameInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_Name **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_Name *local = NULL ;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

    local = pgpasn_NewName(ctx) ; /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceName(ctx, local, buf, buflen, tag, erret);
    if (*erret == kPGPASNError_ErrChoiceBadType) {
        *erret = 0;
        if (local != NULL) pgpasn_FreeName(ctx, local);
        return 0;
    }
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeName(ctx, local);
        return 0;
    }

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


/******************************************************************
 * Routines for PrivateKeyInfo
 ******************************************************************/

size_t pgpasn_SizeofPrivateKeyInfoInternal(
    PGPASN_PrivateKeyInfo *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            pgpasn_SizeofVersionInternal(&asnstruct->version, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofPrivateKeyAlgorithmIdentifierInternal(&asnstruct->privateKeyAlgorithm, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofPrivateKeyInternal(&asnstruct->privateKey, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofAttributesInternal(asnstruct->attributes, PGPASN_TRUE, PGPASN_FALSE) ;

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;

} /* pgpasn_SizeofPrivateKeyInfoInternal */

void pgpasn_DropInPlacePrivateKeyInfo(
    PGPASN_CONTEXT *ctx,
    PGPASN_PrivateKeyInfo *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    pgpasn_DropInPlaceVersion(ctx, &(f->version));
    pgpasn_DropInPlacePrivateKeyAlgorithmIdentifier(ctx, &(f->privateKeyAlgorithm));
    pgpasn_DropInPlacePrivateKey(ctx, &(f->privateKey));
    pgpasn_FreeAttributes(ctx, f->attributes);
    f->attributes = NULL;
} /* pgpasn_DropInPlacePrivateKeyInfo */

size_t pgpasn_PackPrivateKeyInfoInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_PrivateKeyInfo *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofPrivateKeyInfo(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

  do {

    /* field version of PrivateKeyInfo */
    bytesused += pgpasn_PackVersionInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->version), PGPASN_ID_Version, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field privateKeyAlgorithm of PrivateKeyInfo */
    bytesused += pgpasn_PackPrivateKeyAlgorithmIdentifierInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->privateKeyAlgorithm), PGPASN_ID_PrivateKeyAlgorithmIdentifier, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field privateKey of PrivateKeyInfo */
    bytesused += pgpasn_PackPrivateKeyInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->privateKey), PGPASN_ID_PrivateKey, erret);
    if (bytesused > datasize || *erret != 0)
        break;

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

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackPrivateKeyInfoInternal */

size_t pgpasn_UnpkInPlacePrivateKeyInfo(
    PGPASN_CONTEXT *ctx,
    PGPASN_PrivateKeyInfo *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;

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "PrivateKeyInfo" );

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

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

    PGPASN_TRACE_INCR_LEVEL;
  do {

    /* field version of PrivateKeyInfo */
    bytesused += pgpasn_UnpkInPlaceVersion(ctx, &(asnstruct->version), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_Version, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field privateKeyAlgorithm of PrivateKeyInfo */
    bytesused += pgpasn_UnpkInPlacePrivateKeyAlgorithmIdentifier(ctx, &(asnstruct->privateKeyAlgorithm), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_PrivateKeyAlgorithmIdentifier, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field privateKey of PrivateKeyInfo */
    bytesused += pgpasn_UnpkInPlacePrivateKey(ctx, &(asnstruct->privateKey), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_PrivateKey, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field attributes of PrivateKeyInfo */
    if (!indef && bytesused >= localsize) {
        PGPASN_TRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PGPASN_TRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->attributes != NULL)
        pgpasn_FreeAttributes(ctx, asnstruct->attributes);
    bytesused += pgpasn_UnpackAttributesInternal(ctx, &(asnstruct->attributes),
                 buf+bytesused, localsize-bytesused,
                 0x80 | 0x00, erret);
    if (bytesused > localsize || *erret != 0)
        break;

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlacePrivateKeyInfo */

size_t pgpasn_UnpackPrivateKeyInfoInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_PrivateKeyInfo **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_PrivateKeyInfo *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewPrivateKeyInfo(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlacePrivateKeyInfo(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreePrivateKeyInfo(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackPrivateKeyInfoInternal */


/******************************************************************
 * Routines for revokedCertificates_SEQ_OF
 ******************************************************************/

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

    if (asnstruct == NULL)
        return 0;

    lth = asnstruct->n ;
    if (lth > PGPASN_MAX_revokedCertificates_SEQ_OF)
        lth = PGPASN_MAX_revokedCertificates_SEQ_OF;	/* clamp it */
    for (i=0; i<lth; i++)
        body_size += pgpasn_SizeofRevokedCertificateInternal((asnstruct->elt)[i], PGPASN_TRUE, PGPASN_FALSE);

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;
} /* pgpasn_SizeofrevokedCertificates_SEQ_OFInternal */

void pgpasn_DropInPlacerevokedCertificates_SEQ_OF(
    PGPASN_CONTEXT *ctx,
    PGPASN_revokedCertificates_SEQ_OF *f)
{
    long i, lth;

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

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

size_t pgpasn_PackrevokedCertificates_SEQ_OFInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_revokedCertificates_SEQ_OF *asnstruct,
    unsigned char tag,
    int *erret )
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;
    long numElem;
    int i;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

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

    /* lth of the block body */
    datasize = pgpasn_SizeofrevokedCertificates_SEQ_OF(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

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

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun);

    return bytesused;
} /* pgpasn_PackrevokedCertificates_SEQ_OFInternal */

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

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE OF", "revokedCertificates_SEQ_OF");

    if (erret == NULL) return 0;

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }
    bytesused ++; /* consume the tag byte */

    PGPASN_TRACE_INCR_LEVEL;

    bytesused += PGPASN_GetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
            asnstruct->n = -1 ; /* note where (-1 treated as 0) */
            PGPASN_TRACE_DECR_LEVEL;
            return 0;
        }
    }

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

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

        if (asnstruct->elt[i] == NULL)
            asnstruct->elt[i] = pgpasn_NewRevokedCertificate(ctx);
        if (asnstruct->elt[i] == NULL) {
            PGPASN_ERR(kPGPASNError_ErrOutOfMemory);
            break;
        }
        asnstruct->n = i+1 ; /* note the new element */
        bytesused += pgpasn_UnpkInPlaceRevokedCertificate(ctx, asnstruct->elt[i], buf+bytesused,
                            localsize-bytesused, PGPASN_ID_RevokedCertificate, erret);
        if (*erret != 0)
            break;
    } /* for */

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlacerevokedCertificates_SEQ_OF */

size_t pgpasn_UnpackrevokedCertificates_SEQ_OFInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_revokedCertificates_SEQ_OF **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_revokedCertificates_SEQ_OF *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewrevokedCertificates_SEQ_OF(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlacerevokedCertificates_SEQ_OF(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreerevokedCertificates_SEQ_OF(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackrevokedCertificates_SEQ_OFInternal */


/******************************************************************
 * Routines for CertificationRequestInfo
 ******************************************************************/

size_t pgpasn_SizeofCertificationRequestInfoInternal(
    PGPASN_CertificationRequestInfo *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            pgpasn_SizeofVersionInternal(&asnstruct->version, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofNameInternal(&asnstruct->subject, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofSubjectPublicKeyInfoInternal(&asnstruct->subjectPublicKeyInfo, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofAttributesInternal(&asnstruct->attributes, PGPASN_TRUE, PGPASN_FALSE) ;

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;

} /* pgpasn_SizeofCertificationRequestInfoInternal */

void pgpasn_DropInPlaceCertificationRequestInfo(
    PGPASN_CONTEXT *ctx,
    PGPASN_CertificationRequestInfo *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    pgpasn_DropInPlaceVersion(ctx, &(f->version));
    pgpasn_DropInPlaceName(ctx, &(f->subject));
    pgpasn_DropInPlaceSubjectPublicKeyInfo(ctx, &(f->subjectPublicKeyInfo));
    pgpasn_DropInPlaceAttributes(ctx, &(f->attributes));
} /* pgpasn_DropInPlaceCertificationRequestInfo */

size_t pgpasn_PackCertificationRequestInfoInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_CertificationRequestInfo *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofCertificationRequestInfo(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

  do {

    /* field version of CertificationRequestInfo */
    bytesused += pgpasn_PackVersionInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->version), PGPASN_ID_Version, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field subject of CertificationRequestInfo */
    bytesused += pgpasn_PackNameInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->subject), PGPASN_ID_Name, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field subjectPublicKeyInfo of CertificationRequestInfo */
    bytesused += pgpasn_PackSubjectPublicKeyInfoInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->subjectPublicKeyInfo), PGPASN_ID_SubjectPublicKeyInfo, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field attributes of CertificationRequestInfo */
    bytesused += pgpasn_PackAttributesInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->attributes), 0x80 | 0x00, erret);
    if (bytesused > datasize || *erret != 0)
        break;

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackCertificationRequestInfoInternal */

size_t pgpasn_UnpkInPlaceCertificationRequestInfo(
    PGPASN_CONTEXT *ctx,
    PGPASN_CertificationRequestInfo *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;

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "CertificationRequestInfo" );

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

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

    PGPASN_TRACE_INCR_LEVEL;
  do {

    /* field version of CertificationRequestInfo */
    bytesused += pgpasn_UnpkInPlaceVersion(ctx, &(asnstruct->version), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_Version, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field subject of CertificationRequestInfo */
    bytesused += pgpasn_UnpkInPlaceName(ctx, &(asnstruct->subject), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_Name, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field subjectPublicKeyInfo of CertificationRequestInfo */
    bytesused += pgpasn_UnpkInPlaceSubjectPublicKeyInfo(ctx, &(asnstruct->subjectPublicKeyInfo), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_SubjectPublicKeyInfo, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field attributes of CertificationRequestInfo */
    bytesused += pgpasn_UnpkInPlaceAttributes(ctx, &(asnstruct->attributes), buf+bytesused,
                       localsize-bytesused, 0x80 | 0x00, erret);
    if (bytesused > localsize || *erret != 0)
        break;

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceCertificationRequestInfo */

size_t pgpasn_UnpackCertificationRequestInfoInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_CertificationRequestInfo **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_CertificationRequestInfo *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewCertificationRequestInfo(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceCertificationRequestInfo(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeCertificationRequestInfo(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackCertificationRequestInfoInternal */


/******************************************************************
 * Routines for GeneralName
 ******************************************************************/

size_t pgpasn_SizeofGeneralNameInternal(
    PGPASN_GeneralName *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    switch (asnstruct->CHOICE_field_type) {
      case 0x80|0x20|0x00:
        body_size = pgpasn_SizeofOtherNameInternal((PGPASN_OtherName *)(asnstruct->data), PGPASN_TRUE, PGPASN_TRUE);
        break;

      case 0x80|0x20|0x01:
        body_size = pgpasn_SizeofIA5StringInternal((PGPASN_IA5String *)(asnstruct->data), PGPASN_TRUE, PGPASN_TRUE);
        break;

      case 0x80|0x20|0x02:
        body_size = pgpasn_SizeofIA5StringInternal((PGPASN_IA5String *)(asnstruct->data), PGPASN_TRUE, PGPASN_TRUE);
        break;

      case 0x80|0x20|0x04:
        body_size = pgpasn_SizeofNameInternal((PGPASN_Name *)(asnstruct->data), PGPASN_TRUE, PGPASN_TRUE);
        break;

      case 0x80|0x20|0x06:
        body_size = pgpasn_SizeofIA5StringInternal((PGPASN_IA5String *)(asnstruct->data), PGPASN_TRUE, PGPASN_TRUE);
        break;

      case 0x80|0x20|0x07:
        body_size = pgpasn_SizeofOCTET_STRINGInternal((PGPASN_OCTET_STRING *)(asnstruct->data), PGPASN_TRUE, PGPASN_TRUE);
        break;

      case 0x80|0x20|0x08:
        body_size = pgpasn_SizeofOBJECT_IDInternal((PGPASN_OBJECT_ID *)(asnstruct->data), PGPASN_TRUE, PGPASN_TRUE);
        break;

      default:
        break;

    } /* switch */

    (void)outerSizeFlag;
    (void)expTaggedFlag;

    return (body_size);
} /* pgpasn_SizeofGeneralNameInternal */

void pgpasn_DropInPlaceGeneralName(
    PGPASN_CONTEXT *ctx,
    PGPASN_GeneralName *f)
{
    if (ctx == NULL) return;
    if (f == NULL) return;

    switch(f->CHOICE_field_type) {

    case 0x80|0x20|0x00:
        pgpasn_FreeOtherName(ctx, (PGPASN_OtherName *)(f->data) );
        break;
    case 0x80|0x20|0x01:
        pgpasn_FreeIA5String(ctx, (PGPASN_IA5String *)(f->data) );
        break;
    case 0x80|0x20|0x02:
        pgpasn_FreeIA5String(ctx, (PGPASN_IA5String *)(f->data) );
        break;
    case 0x80|0x20|0x04:
        pgpasn_FreeName(ctx, (PGPASN_Name *)(f->data) );
        break;
    case 0x80|0x20|0x06:
        pgpasn_FreeIA5String(ctx, (PGPASN_IA5String *)(f->data) );
        break;
    case 0x80|0x20|0x07:
        pgpasn_FreeOCTET_STRING(ctx, (PGPASN_OCTET_STRING *)(f->data) );
        break;
    case 0x80|0x20|0x08:
        pgpasn_FreeOBJECT_ID(ctx, (PGPASN_OBJECT_ID *)(f->data) );
        break;
    default:
        break;
    } /* switch */

} /* pgpasn_DropInPlaceGeneralName */

size_t pgpasn_PackGeneralNameInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_GeneralName *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofGeneralName(ctx, asnstruct, PGPASN_TRUE);
    if (datasize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

    case 0x80|0x00:
        bytesused += PGPASN_PutTag(buf+bytesused,
                    0x80|0x20|0x00,
                    pgpasn_SizeofOtherName(ctx, (PGPASN_OtherName *)(asnstruct->data),PGPASN_TRUE) );
        bytesused += pgpasn_PackOtherNameInternal(ctx, buf+bytesused, buflen-bytesused,
                       (PGPASN_OtherName *)(asnstruct->data),
                       PGPASN_ID_OtherName, erret);
        break;

    case 0x80|0x01:
        bytesused += PGPASN_PutTag(buf+bytesused,
                    0x80|0x20|0x01,
                    pgpasn_SizeofIA5String(ctx, (PGPASN_IA5String *)(asnstruct->data),PGPASN_TRUE) );
        bytesused += pgpasn_PackIA5StringInternal(ctx, buf+bytesused, buflen-bytesused,
                       (PGPASN_IA5String *)(asnstruct->data),
                       PGPASN_ID_IA5String, erret);
        break;

    case 0x80|0x02:
        bytesused += PGPASN_PutTag(buf+bytesused,
                    0x80|0x20|0x02,
                    pgpasn_SizeofIA5String(ctx, (PGPASN_IA5String *)(asnstruct->data),PGPASN_TRUE) );
        bytesused += pgpasn_PackIA5StringInternal(ctx, buf+bytesused, buflen-bytesused,
                       (PGPASN_IA5String *)(asnstruct->data),
                       PGPASN_ID_IA5String, erret);
        break;

    case 0x80|0x04:
        bytesused += PGPASN_PutTag(buf+bytesused,
                    0x80|0x20|0x04,
                    pgpasn_SizeofName(ctx, (PGPASN_Name *)(asnstruct->data),PGPASN_TRUE) );
        bytesused += pgpasn_PackNameInternal(ctx, buf+bytesused, buflen-bytesused,
                       (PGPASN_Name *)(asnstruct->data),
                       PGPASN_ID_Name, erret);
        break;

    case 0x80|0x06:
        bytesused += PGPASN_PutTag(buf+bytesused,
                    0x80|0x20|0x06,
                    pgpasn_SizeofIA5String(ctx, (PGPASN_IA5String *)(asnstruct->data),PGPASN_TRUE) );
        bytesused += pgpasn_PackIA5StringInternal(ctx, buf+bytesused, buflen-bytesused,
                       (PGPASN_IA5String *)(asnstruct->data),
                       PGPASN_ID_IA5String, erret);
        break;

    case 0x80|0x07:
        bytesused += PGPASN_PutTag(buf+bytesused,
                    0x80|0x20|0x07,
                    pgpasn_SizeofOCTET_STRING(ctx, (PGPASN_OCTET_STRING *)(asnstruct->data),PGPASN_TRUE) );
        bytesused += pgpasn_PackOCTET_STRINGInternal(ctx, buf+bytesused, buflen-bytesused,
                       (PGPASN_OCTET_STRING *)(asnstruct->data),
                       PGPASN_ID_OCTET_STRING, erret);
        break;

    case 0x80|0x08:
        bytesused += PGPASN_PutTag(buf+bytesused,
                    0x80|0x20|0x08,
                    pgpasn_SizeofOBJECT_ID(ctx, (PGPASN_OBJECT_ID *)(asnstruct->data),PGPASN_TRUE) );
        bytesused += pgpasn_PackOBJECT_IDInternal(ctx, buf+bytesused, buflen-bytesused,
                       (PGPASN_OBJECT_ID *)(asnstruct->data),
                       PGPASN_ID_OBJECT_ID, erret);
        break;

    default:
        PGPASN_ERR( kPGPASNError_ErrChoiceBadType );
        break;
    } /* switch */

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

  return bytesused;
} /* pgpasn_PackGeneralNameInternal */

size_t pgpasn_UnpkInPlaceGeneralName(
     PGPASN_CONTEXT *ctx,
     PGPASN_GeneralName *asnstruct,/* output block */
     const unsigned char *buf,
     size_t buflen,
     unsigned char tag,
     int *erret)
{
    (void)tag; /* unused */


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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        return 0;
    }

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

    switch (*buf) {

    /* otherName */
    case 0x80|0x20|0x00:
    {
        size_t bytesused = 0;
        size_t taggeddatasize;
        size_t taggedlocalsize;
        size_t used;

        asnstruct->CHOICE_field_type = *buf;
        used = PGPASN_TakeTag(buf, 0x80|0x20|0x00, &taggeddatasize);
        bytesused += used;

        if ((int)taggeddatasize == -1 && used != 0) {
            PGPASN_TRACE_PRINT_TAG(0x80|0x20|0x00, 0x00);
            PGPASN_TRACE_INCR_LEVEL;
            if (asnstruct->data != NULL)
                pgpasn_FreeOtherName(ctx, asnstruct->data);
            bytesused += pgpasn_UnpackOtherNameInternal(
                            ctx, (PGPASN_OtherName **)&(asnstruct->data),
                            buf+bytesused, buflen-bytesused,
                            PGPASN_ID_OtherName, erret);
            PGPASN_TRACE_DECR_LEVEL;
            if (asnstruct->data == NULL) {
                return 0;
            }
            if ( *(buf+bytesused) != 0x00 &&
                 *(buf+bytesused+1) != 0x00 ) {
                PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
                return 0;
            }
            bytesused += 2;
            return bytesused;
        }
        else if (used > 0) {
            taggedlocalsize = bytesused + taggeddatasize;
            PGPASN_TRACE_PRINT_TAG(0x80|0x20|0x00, 0x00);
            PGPASN_TRACE_INCR_LEVEL;
            if (asnstruct->data != NULL )
                pgpasn_FreeOtherName(ctx, (PGPASN_OtherName *)(asnstruct->data));
            bytesused += pgpasn_UnpackOtherNameInternal(
                            ctx, (PGPASN_OtherName **)&(asnstruct->data),
                            buf+bytesused, taggeddatasize,
                            PGPASN_ID_OtherName, erret);
            PGPASN_TRACE_DECR_LEVEL;
            if (asnstruct->data == NULL) {
                return 0;
            }
            if (bytesused != taggedlocalsize) {
                PGPASN_ERR(kPGPASNError_ErrUnpackTaggedLth);
                return 0;
            }
            return bytesused;
        }
        else {
            PGPASN_TRACE_DECR_LEVEL;
            return 0;
        }
    }
        break;

    /* rfc822Name */
    case 0x80|0x20|0x01:
    {
        size_t bytesused = 0;
        size_t taggeddatasize;
        size_t taggedlocalsize;
        size_t used;

        asnstruct->CHOICE_field_type = *buf;
        used = PGPASN_TakeTag(buf, 0x80|0x20|0x01, &taggeddatasize);
        bytesused += used;

        if ((int)taggeddatasize == -1 && used != 0) {
            PGPASN_TRACE_PRINT_TAG(0x80|0x20|0x01, 0x01);
            PGPASN_TRACE_INCR_LEVEL;
            if (asnstruct->data != NULL)
                pgpasn_FreeIA5String(ctx, asnstruct->data);
            bytesused += pgpasn_UnpackIA5StringInternal(
                            ctx, (PGPASN_IA5String **)&(asnstruct->data),
                            buf+bytesused, buflen-bytesused,
                            PGPASN_ID_IA5String, erret);
            PGPASN_TRACE_DECR_LEVEL;
            if (asnstruct->data == NULL) {
                return 0;
            }
            if ( *(buf+bytesused) != 0x00 &&
                 *(buf+bytesused+1) != 0x00 ) {
                PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
                return 0;
            }
            bytesused += 2;
            return bytesused;
        }
        else if (used > 0) {
            taggedlocalsize = bytesused + taggeddatasize;
            PGPASN_TRACE_PRINT_TAG(0x80|0x20|0x01, 0x01);
            PGPASN_TRACE_INCR_LEVEL;
            if (asnstruct->data != NULL )
                pgpasn_FreeIA5String(ctx, (PGPASN_IA5String *)(asnstruct->data));
            bytesused += pgpasn_UnpackIA5StringInternal(
                            ctx, (PGPASN_IA5String **)&(asnstruct->data),
                            buf+bytesused, taggeddatasize,
                            PGPASN_ID_IA5String, erret);
            PGPASN_TRACE_DECR_LEVEL;
            if (asnstruct->data == NULL) {
                return 0;
            }
            if (bytesused != taggedlocalsize) {
                PGPASN_ERR(kPGPASNError_ErrUnpackTaggedLth);
                return 0;
            }
            return bytesused;
        }
        else {
            PGPASN_TRACE_DECR_LEVEL;
            return 0;
        }
    }
        break;

    /* dNSName */
    case 0x80|0x20|0x02:
    {
        size_t bytesused = 0;
        size_t taggeddatasize;
        size_t taggedlocalsize;
        size_t used;

        asnstruct->CHOICE_field_type = *buf;
        used = PGPASN_TakeTag(buf, 0x80|0x20|0x02, &taggeddatasize);
        bytesused += used;

        if ((int)taggeddatasize == -1 && used != 0) {
            PGPASN_TRACE_PRINT_TAG(0x80|0x20|0x02, 0x02);
            PGPASN_TRACE_INCR_LEVEL;
            if (asnstruct->data != NULL)
                pgpasn_FreeIA5String(ctx, asnstruct->data);
            bytesused += pgpasn_UnpackIA5StringInternal(
                            ctx, (PGPASN_IA5String **)&(asnstruct->data),
                            buf+bytesused, buflen-bytesused,
                            PGPASN_ID_IA5String, erret);
            PGPASN_TRACE_DECR_LEVEL;
            if (asnstruct->data == NULL) {
                return 0;
            }
            if ( *(buf+bytesused) != 0x00 &&
                 *(buf+bytesused+1) != 0x00 ) {
                PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
                return 0;
            }
            bytesused += 2;
            return bytesused;
        }
        else if (used > 0) {
            taggedlocalsize = bytesused + taggeddatasize;
            PGPASN_TRACE_PRINT_TAG(0x80|0x20|0x02, 0x02);
            PGPASN_TRACE_INCR_LEVEL;
            if (asnstruct->data != NULL )
                pgpasn_FreeIA5String(ctx, (PGPASN_IA5String *)(asnstruct->data));
            bytesused += pgpasn_UnpackIA5StringInternal(
                            ctx, (PGPASN_IA5String **)&(asnstruct->data),
                            buf+bytesused, taggeddatasize,
                            PGPASN_ID_IA5String, erret);
            PGPASN_TRACE_DECR_LEVEL;
            if (asnstruct->data == NULL) {
                return 0;
            }
            if (bytesused != taggedlocalsize) {
                PGPASN_ERR(kPGPASNError_ErrUnpackTaggedLth);
                return 0;
            }
            return bytesused;
        }
        else {
            PGPASN_TRACE_DECR_LEVEL;
            return 0;
        }
    }
        break;

    /* directoryName */
    case 0x80|0x20|0x04:
    {
        size_t bytesused = 0;
        size_t taggeddatasize;
        size_t taggedlocalsize;
        size_t used;

        asnstruct->CHOICE_field_type = *buf;
        used = PGPASN_TakeTag(buf, 0x80|0x20|0x04, &taggeddatasize);
        bytesused += used;

        if ((int)taggeddatasize == -1 && used != 0) {
            PGPASN_TRACE_PRINT_TAG(0x80|0x20|0x04, 0x04);
            PGPASN_TRACE_INCR_LEVEL;
            if (asnstruct->data != NULL)
                pgpasn_FreeName(ctx, asnstruct->data);
            bytesused += pgpasn_UnpackNameInternal(
                            ctx, (PGPASN_Name **)&(asnstruct->data),
                            buf+bytesused, buflen-bytesused,
                            PGPASN_ID_Name, erret);
            PGPASN_TRACE_DECR_LEVEL;
            if (asnstruct->data == NULL) {
                return 0;
            }
            if ( *(buf+bytesused) != 0x00 &&
                 *(buf+bytesused+1) != 0x00 ) {
                PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
                return 0;
            }
            bytesused += 2;
            return bytesused;
        }
        else if (used > 0) {
            taggedlocalsize = bytesused + taggeddatasize;
            PGPASN_TRACE_PRINT_TAG(0x80|0x20|0x04, 0x04);
            PGPASN_TRACE_INCR_LEVEL;
            if (asnstruct->data != NULL )
                pgpasn_FreeName(ctx, (PGPASN_Name *)(asnstruct->data));
            bytesused += pgpasn_UnpackNameInternal(
                            ctx, (PGPASN_Name **)&(asnstruct->data),
                            buf+bytesused, taggeddatasize,
                            PGPASN_ID_Name, erret);
            PGPASN_TRACE_DECR_LEVEL;
            if (asnstruct->data == NULL) {
                return 0;
            }
            if (bytesused != taggedlocalsize) {
                PGPASN_ERR(kPGPASNError_ErrUnpackTaggedLth);
                return 0;
            }
            return bytesused;
        }
        else {
            PGPASN_TRACE_DECR_LEVEL;
            return 0;
        }
    }
        break;

    /* uniformResourceIdentifier */
    case 0x80|0x20|0x06:
    {
        size_t bytesused = 0;
        size_t taggeddatasize;
        size_t taggedlocalsize;
        size_t used;

        asnstruct->CHOICE_field_type = *buf;
        used = PGPASN_TakeTag(buf, 0x80|0x20|0x06, &taggeddatasize);
        bytesused += used;

        if ((int)taggeddatasize == -1 && used != 0) {
            PGPASN_TRACE_PRINT_TAG(0x80|0x20|0x06, 0x06);
            PGPASN_TRACE_INCR_LEVEL;
            if (asnstruct->data != NULL)
                pgpasn_FreeIA5String(ctx, asnstruct->data);
            bytesused += pgpasn_UnpackIA5StringInternal(
                            ctx, (PGPASN_IA5String **)&(asnstruct->data),
                            buf+bytesused, buflen-bytesused,
                            PGPASN_ID_IA5String, erret);
            PGPASN_TRACE_DECR_LEVEL;
            if (asnstruct->data == NULL) {
                return 0;
            }
            if ( *(buf+bytesused) != 0x00 &&
                 *(buf+bytesused+1) != 0x00 ) {
                PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
                return 0;
            }
            bytesused += 2;
            return bytesused;
        }
        else if (used > 0) {
            taggedlocalsize = bytesused + taggeddatasize;
            PGPASN_TRACE_PRINT_TAG(0x80|0x20|0x06, 0x06);
            PGPASN_TRACE_INCR_LEVEL;
            if (asnstruct->data != NULL )
                pgpasn_FreeIA5String(ctx, (PGPASN_IA5String *)(asnstruct->data));
            bytesused += pgpasn_UnpackIA5StringInternal(
                            ctx, (PGPASN_IA5String **)&(asnstruct->data),
                            buf+bytesused, taggeddatasize,
                            PGPASN_ID_IA5String, erret);
            PGPASN_TRACE_DECR_LEVEL;
            if (asnstruct->data == NULL) {
                return 0;
            }
            if (bytesused != taggedlocalsize) {
                PGPASN_ERR(kPGPASNError_ErrUnpackTaggedLth);
                return 0;
            }
            return bytesused;
        }
        else {
            PGPASN_TRACE_DECR_LEVEL;
            return 0;
        }
    }
        break;

    /* iPAddress */
    case 0x80|0x20|0x07:
    {
        size_t bytesused = 0;
        size_t taggeddatasize;
        size_t taggedlocalsize;
        size_t used;

        asnstruct->CHOICE_field_type = *buf;
        used = PGPASN_TakeTag(buf, 0x80|0x20|0x07, &taggeddatasize);
        bytesused += used;

        if ((int)taggeddatasize == -1 && used != 0) {
            PGPASN_TRACE_PRINT_TAG(0x80|0x20|0x07, 0x07);
            PGPASN_TRACE_INCR_LEVEL;
            if (asnstruct->data != NULL)
                pgpasn_FreeOCTET_STRING(ctx, asnstruct->data);
            bytesused += pgpasn_UnpackOCTET_STRINGInternal(
                            ctx, (PGPASN_OCTET_STRING **)&(asnstruct->data),
                            buf+bytesused, buflen-bytesused,
                            PGPASN_ID_OCTET_STRING, erret);
            PGPASN_TRACE_DECR_LEVEL;
            if (asnstruct->data == NULL) {
                return 0;
            }
            if ( *(buf+bytesused) != 0x00 &&
                 *(buf+bytesused+1) != 0x00 ) {
                PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
                return 0;
            }
            bytesused += 2;
            return bytesused;
        }
        else if (used > 0) {
            taggedlocalsize = bytesused + taggeddatasize;
            PGPASN_TRACE_PRINT_TAG(0x80|0x20|0x07, 0x07);
            PGPASN_TRACE_INCR_LEVEL;
            if (asnstruct->data != NULL )
                pgpasn_FreeOCTET_STRING(ctx, (PGPASN_OCTET_STRING *)(asnstruct->data));
            bytesused += pgpasn_UnpackOCTET_STRINGInternal(
                            ctx, (PGPASN_OCTET_STRING **)&(asnstruct->data),
                            buf+bytesused, taggeddatasize,
                            PGPASN_ID_OCTET_STRING, erret);
            PGPASN_TRACE_DECR_LEVEL;
            if (asnstruct->data == NULL) {
                return 0;
            }
            if (bytesused != taggedlocalsize) {
                PGPASN_ERR(kPGPASNError_ErrUnpackTaggedLth);
                return 0;
            }
            return bytesused;
        }
        else {
            PGPASN_TRACE_DECR_LEVEL;
            return 0;
        }
    }
        break;

    /* registeredID */
    case 0x80|0x20|0x08:
    {
        size_t bytesused = 0;
        size_t taggeddatasize;
        size_t taggedlocalsize;
        size_t used;

        asnstruct->CHOICE_field_type = *buf;
        used = PGPASN_TakeTag(buf, 0x80|0x20|0x08, &taggeddatasize);
        bytesused += used;

        if ((int)taggeddatasize == -1 && used != 0) {
            PGPASN_TRACE_PRINT_TAG(0x80|0x20|0x08, 0x08);
            PGPASN_TRACE_INCR_LEVEL;
            if (asnstruct->data != NULL)
                pgpasn_FreeOBJECT_ID(ctx, asnstruct->data);
            bytesused += pgpasn_UnpackOBJECT_IDInternal(
                            ctx, (PGPASN_OBJECT_ID **)&(asnstruct->data),
                            buf+bytesused, buflen-bytesused,
                            PGPASN_ID_OBJECT_ID, erret);
            PGPASN_TRACE_DECR_LEVEL;
            if (asnstruct->data == NULL) {
                return 0;
            }
            if ( *(buf+bytesused) != 0x00 &&
                 *(buf+bytesused+1) != 0x00 ) {
                PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
                return 0;
            }
            bytesused += 2;
            return bytesused;
        }
        else if (used > 0) {
            taggedlocalsize = bytesused + taggeddatasize;
            PGPASN_TRACE_PRINT_TAG(0x80|0x20|0x08, 0x08);
            PGPASN_TRACE_INCR_LEVEL;
            if (asnstruct->data != NULL )
                pgpasn_FreeOBJECT_ID(ctx, (PGPASN_OBJECT_ID *)(asnstruct->data));
            bytesused += pgpasn_UnpackOBJECT_IDInternal(
                            ctx, (PGPASN_OBJECT_ID **)&(asnstruct->data),
                            buf+bytesused, taggeddatasize,
                            PGPASN_ID_OBJECT_ID, erret);
            PGPASN_TRACE_DECR_LEVEL;
            if (asnstruct->data == NULL) {
                return 0;
            }
            if (bytesused != taggedlocalsize) {
                PGPASN_ERR(kPGPASNError_ErrUnpackTaggedLth);
                return 0;
            }
            return bytesused;
        }
        else {
            PGPASN_TRACE_DECR_LEVEL;
            return 0;
        }
    }
        break;

    default:
        PGPASN_ERR(kPGPASNError_ErrChoiceBadType);
        return 0;

    } /* switch */

} /* pgpasn_UnpkInPlaceGeneralName */

size_t pgpasn_UnpackGeneralNameInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_GeneralName **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_GeneralName *local = NULL ;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

    local = pgpasn_NewGeneralName(ctx) ; /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceGeneralName(ctx, local, buf, buflen, tag, erret);
    if (*erret == kPGPASNError_ErrChoiceBadType) {
        *erret = 0;
        if (local != NULL) pgpasn_FreeGeneralName(ctx, local);
        return 0;
    }
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeGeneralName(ctx, local);
        return 0;
    }

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


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

size_t pgpasn_SizeofIssuerAndSerialNumberInternal(
    PGPASN_IssuerAndSerialNumber *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            pgpasn_SizeofNameInternal(&asnstruct->issuer, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofCertificateSerialNumberInternal(&asnstruct->serialNumber, PGPASN_TRUE, PGPASN_FALSE) ;

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;

} /* pgpasn_SizeofIssuerAndSerialNumberInternal */

void pgpasn_DropInPlaceIssuerAndSerialNumber(
    PGPASN_CONTEXT *ctx,
    PGPASN_IssuerAndSerialNumber *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    pgpasn_DropInPlaceName(ctx, &(f->issuer));
    pgpasn_DropInPlaceCertificateSerialNumber(ctx, &(f->serialNumber));
} /* pgpasn_DropInPlaceIssuerAndSerialNumber */

size_t pgpasn_PackIssuerAndSerialNumberInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_IssuerAndSerialNumber *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofIssuerAndSerialNumber(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

  do {

    /* field issuer of IssuerAndSerialNumber */
    bytesused += pgpasn_PackNameInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->issuer), PGPASN_ID_Name, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field serialNumber of IssuerAndSerialNumber */
    bytesused += pgpasn_PackCertificateSerialNumberInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->serialNumber), PGPASN_ID_CertificateSerialNumber, erret);
    if (bytesused > datasize || *erret != 0)
        break;

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackIssuerAndSerialNumberInternal */

size_t pgpasn_UnpkInPlaceIssuerAndSerialNumber(
    PGPASN_CONTEXT *ctx,
    PGPASN_IssuerAndSerialNumber *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;

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "IssuerAndSerialNumber" );

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

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

    PGPASN_TRACE_INCR_LEVEL;
  do {

    /* field issuer of IssuerAndSerialNumber */
    bytesused += pgpasn_UnpkInPlaceName(ctx, &(asnstruct->issuer), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_Name, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field serialNumber of IssuerAndSerialNumber */
    bytesused += pgpasn_UnpkInPlaceCertificateSerialNumber(ctx, &(asnstruct->serialNumber), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_CertificateSerialNumber, erret);
    if (bytesused > localsize || *erret != 0)
        break;

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceIssuerAndSerialNumber */

size_t pgpasn_UnpackIssuerAndSerialNumberInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_IssuerAndSerialNumber **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_IssuerAndSerialNumber *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewIssuerAndSerialNumber(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceIssuerAndSerialNumber(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeIssuerAndSerialNumber(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackIssuerAndSerialNumberInternal */


/******************************************************************
 * Routines for TBSCertList
 ******************************************************************/

size_t pgpasn_SizeofTBSCertListInternal(
    PGPASN_TBSCertList *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            pgpasn_SizeofVersionInternal(asnstruct->version, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofAlgorithmIdentifierInternal(&asnstruct->signature, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofNameInternal(&asnstruct->issuer, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofTimeInternal(&asnstruct->thisUpdate, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofTimeInternal(asnstruct->nextUpdate, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofrevokedCertificates_SEQ_OFInternal(asnstruct->revokedCertificates, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofExtensionsInternal(asnstruct->crlExtensions, PGPASN_TRUE, PGPASN_TRUE) ;

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;

} /* pgpasn_SizeofTBSCertListInternal */

void pgpasn_DropInPlaceTBSCertList(
    PGPASN_CONTEXT *ctx,
    PGPASN_TBSCertList *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    pgpasn_FreeVersion(ctx, f->version);
    f->version = NULL;
    pgpasn_DropInPlaceAlgorithmIdentifier(ctx, &(f->signature));
    pgpasn_DropInPlaceName(ctx, &(f->issuer));
    pgpasn_DropInPlaceTime(ctx, &(f->thisUpdate));
    pgpasn_FreeTime(ctx, f->nextUpdate);
    f->nextUpdate = NULL;
    pgpasn_FreerevokedCertificates_SEQ_OF(ctx, f->revokedCertificates);
    f->revokedCertificates = NULL;
    pgpasn_FreeExtensions(ctx, f->crlExtensions);
    f->crlExtensions = NULL;
} /* pgpasn_DropInPlaceTBSCertList */

size_t pgpasn_PackTBSCertListInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_TBSCertList *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofTBSCertList(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

  do {

    /* field version of TBSCertList */
    if (asnstruct->version != NULL) { /* optional */
        bytesused += pgpasn_PackVersionInternal(ctx, buf+bytesused, buflen-bytesused,
                          asnstruct->version, PGPASN_ID_Version, erret );
        if (bytesused > datasize || *erret != 0)
            break;
    }

    /* field signature of TBSCertList */
    bytesused += pgpasn_PackAlgorithmIdentifierInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->signature), PGPASN_ID_AlgorithmIdentifier, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field issuer of TBSCertList */
    bytesused += pgpasn_PackNameInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->issuer), PGPASN_ID_Name, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field thisUpdate of TBSCertList */
    bytesused += pgpasn_PackTimeInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->thisUpdate), PGPASN_ID_Time, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field nextUpdate of TBSCertList */
    if (asnstruct->nextUpdate != NULL) { /* optional */
        bytesused += pgpasn_PackTimeInternal(ctx, buf+bytesused, buflen-bytesused,
                          asnstruct->nextUpdate, PGPASN_ID_Time, erret );
        if (bytesused > datasize || *erret != 0)
            break;
    }

    /* field revokedCertificates of TBSCertList */
    if (asnstruct->revokedCertificates != NULL) { /* optional */
        bytesused += pgpasn_PackrevokedCertificates_SEQ_OFInternal(ctx, buf+bytesused, buflen-bytesused,
                          asnstruct->revokedCertificates, PGPASN_ID_revokedCertificates_SEQ_OF, erret );
        if (bytesused > datasize || *erret != 0)
            break;
    }

    /* field crlExtensions of TBSCertList */
    if (asnstruct->crlExtensions != NULL) { /* optional */
        bytesused += PGPASN_PutTag(buf+bytesused, 0xa0 | 0x00, pgpasn_SizeofExtensions(ctx, asnstruct->crlExtensions, PGPASN_TRUE));
        bytesused += pgpasn_PackExtensionsInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->crlExtensions, PGPASN_ID_Extensions, erret) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackTBSCertListInternal */

size_t pgpasn_UnpkInPlaceTBSCertList(
    PGPASN_CONTEXT *ctx,
    PGPASN_TBSCertList *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;

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "TBSCertList" );

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

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

    PGPASN_TRACE_INCR_LEVEL;
  do {

    /* field version of TBSCertList */
    if (asnstruct->version != NULL)
        pgpasn_FreeVersion(ctx, asnstruct->version);
    bytesused += pgpasn_UnpackVersionInternal(ctx, &(asnstruct->version),
                    buf+bytesused, localsize-bytesused, PGPASN_ID_Version, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field signature of TBSCertList */
    bytesused += pgpasn_UnpkInPlaceAlgorithmIdentifier(ctx, &(asnstruct->signature), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_AlgorithmIdentifier, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field issuer of TBSCertList */
    bytesused += pgpasn_UnpkInPlaceName(ctx, &(asnstruct->issuer), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_Name, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field thisUpdate of TBSCertList */
    bytesused += pgpasn_UnpkInPlaceTime(ctx, &(asnstruct->thisUpdate), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_Time, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field nextUpdate of TBSCertList */
    if (!indef && bytesused >= localsize) {
        PGPASN_TRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PGPASN_TRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->nextUpdate != NULL)
        pgpasn_FreeTime(ctx, asnstruct->nextUpdate);
    bytesused += pgpasn_UnpackTimeInternal(ctx, &(asnstruct->nextUpdate),
                    buf+bytesused, localsize-bytesused, PGPASN_ID_Time, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field revokedCertificates of TBSCertList */
    if (!indef && bytesused >= localsize) {
        PGPASN_TRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PGPASN_TRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->revokedCertificates != NULL)
        pgpasn_FreerevokedCertificates_SEQ_OF(ctx, asnstruct->revokedCertificates);
    bytesused += pgpasn_UnpackrevokedCertificates_SEQ_OFInternal(ctx, &(asnstruct->revokedCertificates),
                    buf+bytesused, localsize-bytesused, PGPASN_ID_revokedCertificates_SEQ_OF, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field crlExtensions of TBSCertList */
    if (!indef && bytesused >= localsize) {
        PGPASN_TRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PGPASN_TRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    { /* local declaration block*/
        size_t taggeddatasize;
        size_t taggedlocalsize;
        size_t used;

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

        if ((int)taggeddatasize == -1 && used != 0) {
            PGPASN_TRACE_PRINT_TAG(0xa0|0x00, 0x00);
            PGPASN_TRACE_INCR_LEVEL;
            if (asnstruct->crlExtensions != NULL)
                pgpasn_FreeExtensions(ctx, asnstruct->crlExtensions);
            bytesused += pgpasn_UnpackExtensionsInternal(ctx, &(asnstruct->crlExtensions),
                    buf+bytesused, localsize-bytesused, PGPASN_ID_Extensions, erret);
            PGPASN_TRACE_DECR_LEVEL;
            if ( *(buf+bytesused) != 0x00 &&
                 *(buf+bytesused+1) != 0x00 ) {
                PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
                break;
            }
            bytesused += 2;
        }

        else if (taggeddatasize > 0 && used != 0) {
            taggedlocalsize = bytesused + taggeddatasize;
            PGPASN_TRACE_PRINT_TAG(0xa0|0x00, 0x00);
            PGPASN_TRACE_INCR_LEVEL;
            if (asnstruct->crlExtensions != NULL)
                pgpasn_FreeExtensions(ctx, asnstruct->crlExtensions);
            bytesused += pgpasn_UnpackExtensionsInternal(ctx, &(asnstruct->crlExtensions),
                       buf+bytesused, localsize-bytesused, PGPASN_ID_Extensions, erret);
            PGPASN_TRACE_DECR_LEVEL;
            if (bytesused != taggedlocalsize) {
                PGPASN_ERR(kPGPASNError_ErrUnpackTaggedLth);
                break;
            }
        }
    } /* for the local declaration block */
    if (bytesused > localsize || *erret != 0)
        break;

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceTBSCertList */

size_t pgpasn_UnpackTBSCertListInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_TBSCertList **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_TBSCertList *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewTBSCertList(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceTBSCertList(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeTBSCertList(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackTBSCertListInternal */


/******************************************************************
 * Routines for TBSCertificate
 ******************************************************************/

size_t pgpasn_SizeofTBSCertificateInternal(
    PGPASN_TBSCertificate *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            pgpasn_SizeofVersionInternal(asnstruct->version, PGPASN_TRUE, PGPASN_TRUE)
          + pgpasn_SizeofCertificateSerialNumberInternal(&asnstruct->serialNumber, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofAlgorithmIdentifierInternal(&asnstruct->signature, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofNameInternal(&asnstruct->issuer, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofValidityInternal(&asnstruct->validity, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofNameInternal(&asnstruct->subject, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofSubjectPublicKeyInfoInternal(&asnstruct->subjectPublicKeyInfo, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofUniqueIdentifierInternal(asnstruct->issuerUniqueID, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofUniqueIdentifierInternal(asnstruct->subjectUniqueID, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofExtensionsInternal(asnstruct->extensions, PGPASN_TRUE, PGPASN_TRUE) ;

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;

} /* pgpasn_SizeofTBSCertificateInternal */

void pgpasn_DropInPlaceTBSCertificate(
    PGPASN_CONTEXT *ctx,
    PGPASN_TBSCertificate *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    pgpasn_FreeVersion(ctx, f->version);
    f->version = NULL;
    pgpasn_DropInPlaceCertificateSerialNumber(ctx, &(f->serialNumber));
    pgpasn_DropInPlaceAlgorithmIdentifier(ctx, &(f->signature));
    pgpasn_DropInPlaceName(ctx, &(f->issuer));
    pgpasn_DropInPlaceValidity(ctx, &(f->validity));
    pgpasn_DropInPlaceName(ctx, &(f->subject));
    pgpasn_DropInPlaceSubjectPublicKeyInfo(ctx, &(f->subjectPublicKeyInfo));
    pgpasn_FreeUniqueIdentifier(ctx, f->issuerUniqueID);
    f->issuerUniqueID = NULL;
    pgpasn_FreeUniqueIdentifier(ctx, f->subjectUniqueID);
    f->subjectUniqueID = NULL;
    pgpasn_FreeExtensions(ctx, f->extensions);
    f->extensions = NULL;
} /* pgpasn_DropInPlaceTBSCertificate */

size_t pgpasn_PackTBSCertificateInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_TBSCertificate *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofTBSCertificate(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

  do {

    /* field version of TBSCertificate */
    if (asnstruct->version != NULL) { /* optional */
        bytesused += PGPASN_PutTag(buf+bytesused, 0xa0 | 0x00, pgpasn_SizeofVersion(ctx, asnstruct->version, PGPASN_TRUE));
        bytesused += pgpasn_PackVersionInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->version, PGPASN_ID_Version, erret) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

    /* field serialNumber of TBSCertificate */
    bytesused += pgpasn_PackCertificateSerialNumberInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->serialNumber), PGPASN_ID_CertificateSerialNumber, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field signature of TBSCertificate */
    bytesused += pgpasn_PackAlgorithmIdentifierInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->signature), PGPASN_ID_AlgorithmIdentifier, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field issuer of TBSCertificate */
    bytesused += pgpasn_PackNameInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->issuer), PGPASN_ID_Name, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field validity of TBSCertificate */
    bytesused += pgpasn_PackValidityInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->validity), PGPASN_ID_Validity, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field subject of TBSCertificate */
    bytesused += pgpasn_PackNameInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->subject), PGPASN_ID_Name, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field subjectPublicKeyInfo of TBSCertificate */
    bytesused += pgpasn_PackSubjectPublicKeyInfoInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->subjectPublicKeyInfo), PGPASN_ID_SubjectPublicKeyInfo, erret);
    if (bytesused > datasize || *erret != 0)
        break;

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

    /* field subjectUniqueID of TBSCertificate */
    if (asnstruct->subjectUniqueID != NULL) { /* optional */
        bytesused += pgpasn_PackUniqueIdentifierInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->subjectUniqueID, 0x80 | 0x02, erret ) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

    /* field extensions of TBSCertificate */
    if (asnstruct->extensions != NULL) { /* optional */
        bytesused += PGPASN_PutTag(buf+bytesused, 0xa0 | 0x03, pgpasn_SizeofExtensions(ctx, asnstruct->extensions, PGPASN_TRUE));
        bytesused += pgpasn_PackExtensionsInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->extensions, PGPASN_ID_Extensions, erret) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackTBSCertificateInternal */

size_t pgpasn_UnpkInPlaceTBSCertificate(
    PGPASN_CONTEXT *ctx,
    PGPASN_TBSCertificate *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;

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "TBSCertificate" );

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

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

    PGPASN_TRACE_INCR_LEVEL;
  do {

    /* field version of TBSCertificate */
    { /* local declaration block*/
        size_t taggeddatasize;
        size_t taggedlocalsize;
        size_t used;

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

        if ((int)taggeddatasize == -1 && used != 0) {
            PGPASN_TRACE_PRINT_TAG(0xa0|0x00, 0x00);
            PGPASN_TRACE_INCR_LEVEL;
            if (asnstruct->version != NULL)
                pgpasn_FreeVersion(ctx, asnstruct->version);
            bytesused += pgpasn_UnpackVersionInternal(ctx, &(asnstruct->version),
                    buf+bytesused, localsize-bytesused, PGPASN_ID_Version, erret);
            PGPASN_TRACE_DECR_LEVEL;
            if ( *(buf+bytesused) != 0x00 &&
                 *(buf+bytesused+1) != 0x00 ) {
                PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
                break;
            }
            bytesused += 2;
        }

        else if (taggeddatasize > 0 && used != 0) {
            taggedlocalsize = bytesused + taggeddatasize;
            PGPASN_TRACE_PRINT_TAG(0xa0|0x00, 0x00);
            PGPASN_TRACE_INCR_LEVEL;
            if (asnstruct->version != NULL)
                pgpasn_FreeVersion(ctx, asnstruct->version);
            bytesused += pgpasn_UnpackVersionInternal(ctx, &(asnstruct->version),
                       buf+bytesused, localsize-bytesused, PGPASN_ID_Version, erret);
            PGPASN_TRACE_DECR_LEVEL;
            if (bytesused != taggedlocalsize) {
                PGPASN_ERR(kPGPASNError_ErrUnpackTaggedLth);
                break;
            }
        }
    } /* for the local declaration block */
    if (bytesused > localsize || *erret != 0)
        break;

    /* field serialNumber of TBSCertificate */
    bytesused += pgpasn_UnpkInPlaceCertificateSerialNumber(ctx, &(asnstruct->serialNumber), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_CertificateSerialNumber, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field signature of TBSCertificate */
    bytesused += pgpasn_UnpkInPlaceAlgorithmIdentifier(ctx, &(asnstruct->signature), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_AlgorithmIdentifier, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field issuer of TBSCertificate */
    bytesused += pgpasn_UnpkInPlaceName(ctx, &(asnstruct->issuer), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_Name, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field validity of TBSCertificate */
    bytesused += pgpasn_UnpkInPlaceValidity(ctx, &(asnstruct->validity), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_Validity, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field subject of TBSCertificate */
    bytesused += pgpasn_UnpkInPlaceName(ctx, &(asnstruct->subject), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_Name, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field subjectPublicKeyInfo of TBSCertificate */
    bytesused += pgpasn_UnpkInPlaceSubjectPublicKeyInfo(ctx, &(asnstruct->subjectPublicKeyInfo), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_SubjectPublicKeyInfo, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field issuerUniqueID of TBSCertificate */
    if (!indef && bytesused >= localsize) {
        PGPASN_TRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PGPASN_TRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->issuerUniqueID != NULL)
        pgpasn_FreeUniqueIdentifier(ctx, asnstruct->issuerUniqueID);
    bytesused += pgpasn_UnpackUniqueIdentifierInternal(ctx, &(asnstruct->issuerUniqueID),
                 buf+bytesused, localsize-bytesused,
                 0x80 | 0x01, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field subjectUniqueID of TBSCertificate */
    if (!indef && bytesused >= localsize) {
        PGPASN_TRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PGPASN_TRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->subjectUniqueID != NULL)
        pgpasn_FreeUniqueIdentifier(ctx, asnstruct->subjectUniqueID);
    bytesused += pgpasn_UnpackUniqueIdentifierInternal(ctx, &(asnstruct->subjectUniqueID),
                 buf+bytesused, localsize-bytesused,
                 0x80 | 0x02, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field extensions of TBSCertificate */
    if (!indef && bytesused >= localsize) {
        PGPASN_TRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PGPASN_TRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    { /* local declaration block*/
        size_t taggeddatasize;
        size_t taggedlocalsize;
        size_t used;

        used = PGPASN_TakeTag(buf+bytesused, 0xa0 | 0x03,
                          &taggeddatasize);
        bytesused += used;

        if ((int)taggeddatasize == -1 && used != 0) {
            PGPASN_TRACE_PRINT_TAG(0xa0|0x03, 0x03);
            PGPASN_TRACE_INCR_LEVEL;
            if (asnstruct->extensions != NULL)
                pgpasn_FreeExtensions(ctx, asnstruct->extensions);
            bytesused += pgpasn_UnpackExtensionsInternal(ctx, &(asnstruct->extensions),
                    buf+bytesused, localsize-bytesused, PGPASN_ID_Extensions, erret);
            PGPASN_TRACE_DECR_LEVEL;
            if ( *(buf+bytesused) != 0x00 &&
                 *(buf+bytesused+1) != 0x00 ) {
                PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
                break;
            }
            bytesused += 2;
        }

        else if (taggeddatasize > 0 && used != 0) {
            taggedlocalsize = bytesused + taggeddatasize;
            PGPASN_TRACE_PRINT_TAG(0xa0|0x03, 0x03);
            PGPASN_TRACE_INCR_LEVEL;
            if (asnstruct->extensions != NULL)
                pgpasn_FreeExtensions(ctx, asnstruct->extensions);
            bytesused += pgpasn_UnpackExtensionsInternal(ctx, &(asnstruct->extensions),
                       buf+bytesused, localsize-bytesused, PGPASN_ID_Extensions, erret);
            PGPASN_TRACE_DECR_LEVEL;
            if (bytesused != taggedlocalsize) {
                PGPASN_ERR(kPGPASNError_ErrUnpackTaggedLth);
                break;
            }
        }
    } /* for the local declaration block */
    if (bytesused > localsize || *erret != 0)
        break;

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceTBSCertificate */

size_t pgpasn_UnpackTBSCertificateInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_TBSCertificate **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_TBSCertificate *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewTBSCertificate(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceTBSCertificate(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeTBSCertificate(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackTBSCertificateInternal */


/******************************************************************
 * Routines for Certificate
 ******************************************************************/

size_t pgpasn_SizeofCertificateInternal(
    PGPASN_Certificate *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            pgpasn_SizeofTBSCertificateInternal(&asnstruct->tbsCertificate, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofAlgorithmIdentifierInternal(&asnstruct->signatureAlgorithm, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofBIT_STRINGInternal(&asnstruct->signature, PGPASN_TRUE, PGPASN_FALSE) ;

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;

} /* pgpasn_SizeofCertificateInternal */

void pgpasn_DropInPlaceCertificate(
    PGPASN_CONTEXT *ctx,
    PGPASN_Certificate *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    pgpasn_DropInPlaceTBSCertificate(ctx, &(f->tbsCertificate));
    pgpasn_DropInPlaceAlgorithmIdentifier(ctx, &(f->signatureAlgorithm));
    pgpasn_DropInPlaceBIT_STRING(ctx, &(f->signature));
} /* pgpasn_DropInPlaceCertificate */

size_t pgpasn_PackCertificateInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_Certificate *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofCertificate(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

  do {

    /* field tbsCertificate of Certificate */
    bytesused += pgpasn_PackTBSCertificateInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->tbsCertificate), PGPASN_ID_TBSCertificate, erret);
    if (bytesused > datasize || *erret != 0)
        break;

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

    /* field signature of Certificate */
    bytesused += pgpasn_PackBIT_STRINGInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->signature), PGPASN_ID_BIT_STRING, erret);
    if (bytesused > datasize || *erret != 0)
        break;

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackCertificateInternal */

size_t pgpasn_UnpkInPlaceCertificate(
    PGPASN_CONTEXT *ctx,
    PGPASN_Certificate *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;

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "Certificate" );

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

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

    PGPASN_TRACE_INCR_LEVEL;
  do {

    /* field tbsCertificate of Certificate */
    bytesused += pgpasn_UnpkInPlaceTBSCertificate(ctx, &(asnstruct->tbsCertificate), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_TBSCertificate, erret);
    if (bytesused > localsize || *erret != 0)
        break;

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

    /* field signature of Certificate */
    bytesused += pgpasn_UnpkInPlaceBIT_STRING(ctx, &(asnstruct->signature), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_BIT_STRING, erret);
    if (bytesused > localsize || *erret != 0)
        break;

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceCertificate */

size_t pgpasn_UnpackCertificateInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_Certificate **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_Certificate *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewCertificate(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceCertificate(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeCertificate(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackCertificateInternal */


/******************************************************************
 * Routines for CertificateRevocationList
 ******************************************************************/

size_t pgpasn_SizeofCertificateRevocationListInternal(
    PGPASN_CertificateRevocationList *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            pgpasn_SizeofTBSCertListInternal(&asnstruct->tbsCertList, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofAlgorithmIdentifierInternal(&asnstruct->signatureAlgorithm, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofBIT_STRINGInternal(&asnstruct->signature, PGPASN_TRUE, PGPASN_FALSE) ;

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;

} /* pgpasn_SizeofCertificateRevocationListInternal */

void pgpasn_DropInPlaceCertificateRevocationList(
    PGPASN_CONTEXT *ctx,
    PGPASN_CertificateRevocationList *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    pgpasn_DropInPlaceTBSCertList(ctx, &(f->tbsCertList));
    pgpasn_DropInPlaceAlgorithmIdentifier(ctx, &(f->signatureAlgorithm));
    pgpasn_DropInPlaceBIT_STRING(ctx, &(f->signature));
} /* pgpasn_DropInPlaceCertificateRevocationList */

size_t pgpasn_PackCertificateRevocationListInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_CertificateRevocationList *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofCertificateRevocationList(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

  do {

    /* field tbsCertList of CertificateRevocationList */
    bytesused += pgpasn_PackTBSCertListInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->tbsCertList), PGPASN_ID_TBSCertList, erret);
    if (bytesused > datasize || *erret != 0)
        break;

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

    /* field signature of CertificateRevocationList */
    bytesused += pgpasn_PackBIT_STRINGInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->signature), PGPASN_ID_BIT_STRING, erret);
    if (bytesused > datasize || *erret != 0)
        break;

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackCertificateRevocationListInternal */

size_t pgpasn_UnpkInPlaceCertificateRevocationList(
    PGPASN_CONTEXT *ctx,
    PGPASN_CertificateRevocationList *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;

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "CertificateRevocationList" );

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

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

    PGPASN_TRACE_INCR_LEVEL;
  do {

    /* field tbsCertList of CertificateRevocationList */
    bytesused += pgpasn_UnpkInPlaceTBSCertList(ctx, &(asnstruct->tbsCertList), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_TBSCertList, erret);
    if (bytesused > localsize || *erret != 0)
        break;

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

    /* field signature of CertificateRevocationList */
    bytesused += pgpasn_UnpkInPlaceBIT_STRING(ctx, &(asnstruct->signature), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_BIT_STRING, erret);
    if (bytesused > localsize || *erret != 0)
        break;

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceCertificateRevocationList */

size_t pgpasn_UnpackCertificateRevocationListInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_CertificateRevocationList **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_CertificateRevocationList *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewCertificateRevocationList(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceCertificateRevocationList(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeCertificateRevocationList(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackCertificateRevocationListInternal */


/******************************************************************
 * Routines for CertificationRequest
 ******************************************************************/

size_t pgpasn_SizeofCertificationRequestInternal(
    PGPASN_CertificationRequest *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            pgpasn_SizeofCertificationRequestInfoInternal(&asnstruct->certificationRequestInfo, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofSignatureAlgorithmIdentifierInternal(&asnstruct->signatureAlgorithm, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofSignatureInternal(&asnstruct->signature, PGPASN_TRUE, PGPASN_FALSE) ;

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;

} /* pgpasn_SizeofCertificationRequestInternal */

void pgpasn_DropInPlaceCertificationRequest(
    PGPASN_CONTEXT *ctx,
    PGPASN_CertificationRequest *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    pgpasn_DropInPlaceCertificationRequestInfo(ctx, &(f->certificationRequestInfo));
    pgpasn_DropInPlaceSignatureAlgorithmIdentifier(ctx, &(f->signatureAlgorithm));
    pgpasn_DropInPlaceSignature(ctx, &(f->signature));
} /* pgpasn_DropInPlaceCertificationRequest */

size_t pgpasn_PackCertificationRequestInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_CertificationRequest *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofCertificationRequest(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

  do {

    /* field certificationRequestInfo of CertificationRequest */
    bytesused += pgpasn_PackCertificationRequestInfoInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->certificationRequestInfo), PGPASN_ID_CertificationRequestInfo, erret);
    if (bytesused > datasize || *erret != 0)
        break;

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

    /* field signature of CertificationRequest */
    bytesused += pgpasn_PackSignatureInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->signature), PGPASN_ID_Signature, erret);
    if (bytesused > datasize || *erret != 0)
        break;

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackCertificationRequestInternal */

size_t pgpasn_UnpkInPlaceCertificationRequest(
    PGPASN_CONTEXT *ctx,
    PGPASN_CertificationRequest *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;

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "CertificationRequest" );

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

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

    PGPASN_TRACE_INCR_LEVEL;
  do {

    /* field certificationRequestInfo of CertificationRequest */
    bytesused += pgpasn_UnpkInPlaceCertificationRequestInfo(ctx, &(asnstruct->certificationRequestInfo), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_CertificationRequestInfo, erret);
    if (bytesused > localsize || *erret != 0)
        break;

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

    /* field signature of CertificationRequest */
    bytesused += pgpasn_UnpkInPlaceSignature(ctx, &(asnstruct->signature), buf+bytesused,
                        localsize-bytesused, PGPASN_ID_Signature, erret);
    if (bytesused > localsize || *erret != 0)
        break;

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceCertificationRequest */

size_t pgpasn_UnpackCertificationRequestInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_CertificationRequest **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_CertificationRequest *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewCertificationRequest(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceCertificationRequest(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeCertificationRequest(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackCertificationRequestInternal */


/******************************************************************
 * Routines for GeneralNames
 ******************************************************************/

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

    if (asnstruct == NULL)
        return 0;

    lth = asnstruct->n ;
    if (lth > PGPASN_MAX_GeneralNames)
        lth = PGPASN_MAX_GeneralNames;	/* clamp it */
    for (i=0; i<lth; i++)
        body_size += pgpasn_SizeofGeneralNameInternal((asnstruct->elt)[i], PGPASN_TRUE, PGPASN_FALSE);

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;
} /* pgpasn_SizeofGeneralNamesInternal */

void pgpasn_DropInPlaceGeneralNames(
    PGPASN_CONTEXT *ctx,
    PGPASN_GeneralNames *f)
{
    long i, lth;

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

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

size_t pgpasn_PackGeneralNamesInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_GeneralNames *asnstruct,
    unsigned char tag,
    int *erret )
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;
    long numElem;
    int i;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

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

    /* lth of the block body */
    datasize = pgpasn_SizeofGeneralNames(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

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

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun);

    return bytesused;
} /* pgpasn_PackGeneralNamesInternal */

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

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE OF", "GeneralNames");

    if (erret == NULL) return 0;

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }
    bytesused ++; /* consume the tag byte */

    PGPASN_TRACE_INCR_LEVEL;

    bytesused += PGPASN_GetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
            asnstruct->n = -1 ; /* note where (-1 treated as 0) */
            PGPASN_TRACE_DECR_LEVEL;
            return 0;
        }
    }

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

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

        if (asnstruct->elt[i] == NULL)
            asnstruct->elt[i] = pgpasn_NewGeneralName(ctx);
        if (asnstruct->elt[i] == NULL) {
            PGPASN_ERR(kPGPASNError_ErrOutOfMemory);
            break;
        }
        asnstruct->n = i+1 ; /* note the new element */
        bytesused += pgpasn_UnpkInPlaceGeneralName(ctx, asnstruct->elt[i], buf+bytesused,
                            localsize-bytesused, PGPASN_ID_GeneralName, erret);
        if (*erret != 0)
            break;
    } /* for */

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceGeneralNames */

size_t pgpasn_UnpackGeneralNamesInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_GeneralNames **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_GeneralNames *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewGeneralNames(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceGeneralNames(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeGeneralNames(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackGeneralNamesInternal */


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

size_t pgpasn_SizeofSignerInfoInternal(
    PGPASN_SignerInfo *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            pgpasn_SizeofVersionInternal(&asnstruct->version, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofIssuerAndSerialNumberInternal(&asnstruct->issuerAndSerialNumber, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofDigestAlgorithmIdentifierInternal(&asnstruct->digestAlgorithm, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofAttributesInternal(asnstruct->authenticatedAttributes, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofDigestEncryptionAlgorithmIdentifierInternal(&asnstruct->digestEncryptionAlgorithm, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofEncryptedDigestInternal(&asnstruct->encryptedDigest, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofAttributesInternal(asnstruct->unauthenticatedAttributes, PGPASN_TRUE, PGPASN_FALSE) ;

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;

} /* pgpasn_SizeofSignerInfoInternal */

void pgpasn_DropInPlaceSignerInfo(
    PGPASN_CONTEXT *ctx,
    PGPASN_SignerInfo *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    pgpasn_DropInPlaceVersion(ctx, &(f->version));
    pgpasn_DropInPlaceIssuerAndSerialNumber(ctx, &(f->issuerAndSerialNumber));
    pgpasn_DropInPlaceDigestAlgorithmIdentifier(ctx, &(f->digestAlgorithm));
    pgpasn_FreeAttributes(ctx, f->authenticatedAttributes);
    f->authenticatedAttributes = NULL;
    pgpasn_DropInPlaceDigestEncryptionAlgorithmIdentifier(ctx, &(f->digestEncryptionAlgorithm));
    pgpasn_DropInPlaceEncryptedDigest(ctx, &(f->encryptedDigest));
    pgpasn_FreeAttributes(ctx, f->unauthenticatedAttributes);
    f->unauthenticatedAttributes = NULL;
} /* pgpasn_DropInPlaceSignerInfo */

size_t pgpasn_PackSignerInfoInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_SignerInfo *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofSignerInfo(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

  do {

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

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

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

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

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

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

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

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackSignerInfoInternal */

size_t pgpasn_UnpkInPlaceSignerInfo(
    PGPASN_CONTEXT *ctx,
    PGPASN_SignerInfo *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;

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "SignerInfo" );

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

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

    PGPASN_TRACE_INCR_LEVEL;
  do {

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

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

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

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

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

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

    /* field unauthenticatedAttributes of SignerInfo */
    if (!indef && bytesused >= localsize) {
        PGPASN_TRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PGPASN_TRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->unauthenticatedAttributes != NULL)
        pgpasn_FreeAttributes(ctx, asnstruct->unauthenticatedAttributes);
    bytesused += pgpasn_UnpackAttributesInternal(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 ) {
            PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
            break;
        }
        bytesused += 2;
    }
  } while(0);

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceSignerInfo */

size_t pgpasn_UnpackSignerInfoInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_SignerInfo **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_SignerInfo *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewSignerInfo(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceSignerInfo(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeSignerInfo(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackSignerInfoInternal */


/******************************************************************
 * Routines for CertificateRevocationLists
 ******************************************************************/

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

    if (asnstruct == NULL)
        return 0;

    lth = asnstruct->n;
    if (lth > PGPASN_MAX_CertificateRevocationLists)
        lth = PGPASN_MAX_CertificateRevocationLists;	/* clamp it */
    for (i=0;i<lth;i++)
        body_size += pgpasn_SizeofCertificateRevocationListInternal((asnstruct->elt)[i], PGPASN_TRUE, PGPASN_FALSE);

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;
} /* pgpasn_SizeofCertificateRevocationListsInternal */

void pgpasn_DropInPlaceCertificateRevocationLists(
    PGPASN_CONTEXT *ctx,
    PGPASN_CertificateRevocationLists *f)
{
    long i, lth;

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

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

size_t pgpasn_PackCertificateRevocationListsInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_CertificateRevocationLists *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;
    PGPASN_VariableBlock temp[PGPASN_MAX_CertificateRevocationLists];

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

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

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

    datasize = pgpasn_SizeofCertificateRevocationLists(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

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

    else {

        /* calculate lengths and max */
        for (i=0; i<numElem; i++) {
            length = pgpasn_SizeofCertificateRevocationList(ctx, (asnstruct->elt)[i], PGPASN_TRUE);
            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 *)PGPASN_Alloc(ctx->memMgr, max);
            memset(temp[i].val, 0, max);
            (void) pgpasn_PackCertificateRevocationListInternal(ctx, temp[i].val,
                          max, (asnstruct->elt)[i],
                          PGPASN_ID_CertificateRevocationList, erret );
            if (*erret != 0) {
                for (j=0; j<i; j++)
                    PGPASN_Free(ctx->memMgr, temp[j].val);
                return 0;
            }
        }

        /* sort and look for duplicates */
        qsort(temp, numElem, sizeof(PGPASN_VariableBlock), PGPASN_CompareElems);
        for (i=0; i<(numElem-1); i++)
            if (memcmp(temp[i].val, temp[i+1].val, max) == 0) {
                PGPASN_ERR(kPGPASNError_ErrPackSETOFUnsortable);
                for (j=0; j<i; j++)
                    PGPASN_Free(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;
            PGPASN_Free(ctx->memMgr, temp[i].val);
        }
    }

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackCertificateRevocationListsInternal */

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

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x31, "SET OF", "CertificateRevocationLists");

    if (erret == NULL) return 0;

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

    bytesused += PGPASN_GetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
            asnstruct->n = -1 ; /* note where (-1 treated as 0) */
            PGPASN_TRACE_DECR_LEVEL;
            return 0;
        }
    }

    for (i=0; (i < PGPASN_MAX_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] = pgpasn_NewCertificateRevocationList(ctx);
        if (asnstruct->elt[i] == NULL) {
            PGPASN_ERR(kPGPASNError_ErrOutOfMemory);
            break;
        }
        asnstruct->n = i+1 ; /* note the new element */
        bytesused += pgpasn_UnpkInPlaceCertificateRevocationList(ctx, asnstruct->elt[i],
                          buf+bytesused, localsize-bytesused,
                          PGPASN_ID_CertificateRevocationList, erret);
        if (*erret != 0)
            break;
    } /* for */

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceCertificateRevocationLists */

size_t pgpasn_UnpackCertificateRevocationListsInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_CertificateRevocationLists **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_CertificateRevocationLists *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewCertificateRevocationLists(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceCertificateRevocationLists(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeCertificateRevocationLists(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackCertificateRevocationListsInternal */


/******************************************************************
 * Routines for Certificates
 ******************************************************************/

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

    if (asnstruct == NULL)
        return 0;

    lth = asnstruct->n;
    if (lth > PGPASN_MAX_Certificates)
        lth = PGPASN_MAX_Certificates;	/* clamp it */
    for (i=0;i<lth;i++)
        body_size += pgpasn_SizeofCertificateInternal((asnstruct->elt)[i], PGPASN_TRUE, PGPASN_FALSE);

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;
} /* pgpasn_SizeofCertificatesInternal */

void pgpasn_DropInPlaceCertificates(
    PGPASN_CONTEXT *ctx,
    PGPASN_Certificates *f)
{
    long i, lth;

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

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

size_t pgpasn_PackCertificatesInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_Certificates *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;
    PGPASN_VariableBlock temp[PGPASN_MAX_Certificates];

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

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

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

    datasize = pgpasn_SizeofCertificates(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

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

    else {

        /* calculate lengths and max */
        for (i=0; i<numElem; i++) {
            length = pgpasn_SizeofCertificate(ctx, (asnstruct->elt)[i], PGPASN_TRUE);
            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 *)PGPASN_Alloc(ctx->memMgr, max);
            memset(temp[i].val, 0, max);
            (void) pgpasn_PackCertificateInternal(ctx, temp[i].val,
                          max, (asnstruct->elt)[i],
                          PGPASN_ID_Certificate, erret );
            if (*erret != 0) {
                for (j=0; j<i; j++)
                    PGPASN_Free(ctx->memMgr, temp[j].val);
                return 0;
            }
        }

        /* sort and look for duplicates */
        qsort(temp, numElem, sizeof(PGPASN_VariableBlock), PGPASN_CompareElems);
        for (i=0; i<(numElem-1); i++)
            if (memcmp(temp[i].val, temp[i+1].val, max) == 0) {
                PGPASN_ERR(kPGPASNError_ErrPackSETOFUnsortable);
                for (j=0; j<i; j++)
                    PGPASN_Free(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;
            PGPASN_Free(ctx->memMgr, temp[i].val);
        }
    }

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackCertificatesInternal */

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

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x31, "SET OF", "Certificates");

    if (erret == NULL) return 0;

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

    bytesused += PGPASN_GetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
            asnstruct->n = -1 ; /* note where (-1 treated as 0) */
            PGPASN_TRACE_DECR_LEVEL;
            return 0;
        }
    }

    for (i=0; (i < PGPASN_MAX_Certificates) && (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] = pgpasn_NewCertificate(ctx);
        if (asnstruct->elt[i] == NULL) {
            PGPASN_ERR(kPGPASNError_ErrOutOfMemory);
            break;
        }
        asnstruct->n = i+1 ; /* note the new element */
        bytesused += pgpasn_UnpkInPlaceCertificate(ctx, asnstruct->elt[i],
                          buf+bytesused, localsize-bytesused,
                          PGPASN_ID_Certificate, erret);
        if (*erret != 0)
            break;
    } /* for */

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceCertificates */

size_t pgpasn_UnpackCertificatesInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_Certificates **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_Certificates *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewCertificates(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceCertificates(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeCertificates(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackCertificatesInternal */


/******************************************************************
 * Routines for DistributionPointName
 ******************************************************************/

size_t pgpasn_SizeofDistributionPointNameInternal(
    PGPASN_DistributionPointName *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    switch (asnstruct->CHOICE_field_type) {
      case 0x80|0x00:
      case 0x80|0x20|0x00:
        body_size = pgpasn_SizeofGeneralNamesInternal((PGPASN_GeneralNames *)(asnstruct->data), outerSizeFlag, expTaggedFlag);
        break;

      case 0x80|0x01:
      case 0x80|0x20|0x01:
        body_size = pgpasn_SizeofRelativeDistinguishedNameInternal((PGPASN_RelativeDistinguishedName *)(asnstruct->data), outerSizeFlag, expTaggedFlag);
        break;

      default:
        break;

    } /* switch */

    return (body_size);
} /* pgpasn_SizeofDistributionPointNameInternal */

void pgpasn_DropInPlaceDistributionPointName(
    PGPASN_CONTEXT *ctx,
    PGPASN_DistributionPointName *f)
{
    if (ctx == NULL) return;
    if (f == NULL) return;

    switch(f->CHOICE_field_type) {

    case 0x80|0x00:
    case 0x80|0x20|0x00:
        pgpasn_FreeGeneralNames(ctx, (PGPASN_GeneralNames *)(f->data));
        break;
    case 0x80|0x01:
    case 0x80|0x20|0x01:
        pgpasn_FreeRelativeDistinguishedName(ctx, (PGPASN_RelativeDistinguishedName *)(f->data));
        break;
    default:
        break;
    } /* switch */

} /* pgpasn_DropInPlaceDistributionPointName */

size_t pgpasn_PackDistributionPointNameInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_DistributionPointName *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofDistributionPointName(ctx, asnstruct, PGPASN_TRUE);
    if (datasize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

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

    case 0x80|0x01:
        bytesused += pgpasn_PackRelativeDistinguishedNameInternal(ctx, buf+bytesused, buflen-bytesused,
                      (PGPASN_RelativeDistinguishedName *)(asnstruct->data),
                      0x80|0x01,
                      erret);
        break;

    default:
        PGPASN_ERR( kPGPASNError_ErrChoiceBadType );
        break;
    } /* switch */

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

  return bytesused;
} /* pgpasn_PackDistributionPointNameInternal */

size_t pgpasn_UnpkInPlaceDistributionPointName(
     PGPASN_CONTEXT *ctx,
     PGPASN_DistributionPointName *asnstruct,/* output block */
     const unsigned char *buf,
     size_t buflen,
     unsigned char tag,
     int *erret)
{
    (void)tag; /* unused */


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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        return 0;
    }

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

    switch (*buf) {

    /* fullName */
    case 0x80|0x00:
    case 0x80|0x20|0x00:
        asnstruct->CHOICE_field_type = *buf;
        asnstruct->data = (void *)pgpasn_NewGeneralNames(ctx);
        if (asnstruct->data == NULL) {
            PGPASN_ERR(kPGPASNError_ErrOutOfMemory);
            return 0;
        }
        return (pgpasn_UnpkInPlaceGeneralNames(ctx, (PGPASN_GeneralNames *)(asnstruct->data),
                    buf, buflen,
                    0x80|0x00, erret));
        /*NOTREACHED*/
        break;

    /* nameRelativeToCRLIssuer */
    case 0x80|0x01:
    case 0x80|0x20|0x01:
        asnstruct->CHOICE_field_type = *buf;
        asnstruct->data = (void *)pgpasn_NewRelativeDistinguishedName(ctx);
        if (asnstruct->data == NULL) {
            PGPASN_ERR(kPGPASNError_ErrOutOfMemory);
            return 0;
        }
        return (pgpasn_UnpkInPlaceRelativeDistinguishedName(ctx, (PGPASN_RelativeDistinguishedName *)(asnstruct->data),
                    buf, buflen,
                    0x80|0x01, erret));
        /*NOTREACHED*/
        break;

    default:
        PGPASN_ERR(kPGPASNError_ErrChoiceBadType);
        return 0;

    } /* switch */

} /* pgpasn_UnpkInPlaceDistributionPointName */

size_t pgpasn_UnpackDistributionPointNameInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_DistributionPointName **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_DistributionPointName *local = NULL ;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

    local = pgpasn_NewDistributionPointName(ctx) ; /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceDistributionPointName(ctx, local, buf, buflen, tag, erret);
    if (*erret == kPGPASNError_ErrChoiceBadType) {
        *erret = 0;
        if (local != NULL) pgpasn_FreeDistributionPointName(ctx, local);
        return 0;
    }
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeDistributionPointName(ctx, local);
        return 0;
    }

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


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

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

    if (asnstruct == NULL)
        return 0;

    lth = asnstruct->n;
    if (lth > PGPASN_MAX_SignerInfos)
        lth = PGPASN_MAX_SignerInfos;	/* clamp it */
    for (i=0;i<lth;i++)
        body_size += pgpasn_SizeofSignerInfoInternal((asnstruct->elt)[i], PGPASN_TRUE, PGPASN_FALSE);

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;
} /* pgpasn_SizeofSignerInfosInternal */

void pgpasn_DropInPlaceSignerInfos(
    PGPASN_CONTEXT *ctx,
    PGPASN_SignerInfos *f)
{
    long i, lth;

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

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

size_t pgpasn_PackSignerInfosInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_SignerInfos *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;
    PGPASN_VariableBlock temp[PGPASN_MAX_SignerInfos];

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

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

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

    datasize = pgpasn_SizeofSignerInfos(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

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

    else {

        /* calculate lengths and max */
        for (i=0; i<numElem; i++) {
            length = pgpasn_SizeofSignerInfo(ctx, (asnstruct->elt)[i], PGPASN_TRUE);
            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 *)PGPASN_Alloc(ctx->memMgr, max);
            memset(temp[i].val, 0, max);
            (void) pgpasn_PackSignerInfoInternal(ctx, temp[i].val,
                          max, (asnstruct->elt)[i],
                          PGPASN_ID_SignerInfo, erret );
            if (*erret != 0) {
                for (j=0; j<i; j++)
                    PGPASN_Free(ctx->memMgr, temp[j].val);
                return 0;
            }
        }

        /* sort and look for duplicates */
        qsort(temp, numElem, sizeof(PGPASN_VariableBlock), PGPASN_CompareElems);
        for (i=0; i<(numElem-1); i++)
            if (memcmp(temp[i].val, temp[i+1].val, max) == 0) {
                PGPASN_ERR(kPGPASNError_ErrPackSETOFUnsortable);
                for (j=0; j<i; j++)
                    PGPASN_Free(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;
            PGPASN_Free(ctx->memMgr, temp[i].val);
        }
    }

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackSignerInfosInternal */

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

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x31, "SET OF", "SignerInfos");

    if (erret == NULL) return 0;

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

    bytesused += PGPASN_GetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
            asnstruct->n = -1 ; /* note where (-1 treated as 0) */
            PGPASN_TRACE_DECR_LEVEL;
            return 0;
        }
    }

    for (i=0; (i < PGPASN_MAX_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] = pgpasn_NewSignerInfo(ctx);
        if (asnstruct->elt[i] == NULL) {
            PGPASN_ERR(kPGPASNError_ErrOutOfMemory);
            break;
        }
        asnstruct->n = i+1 ; /* note the new element */
        bytesused += pgpasn_UnpkInPlaceSignerInfo(ctx, asnstruct->elt[i],
                          buf+bytesused, localsize-bytesused,
                          PGPASN_ID_SignerInfo, erret);
        if (*erret != 0)
            break;
    } /* for */

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceSignerInfos */

size_t pgpasn_UnpackSignerInfosInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_SignerInfos **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_SignerInfos *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewSignerInfos(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceSignerInfos(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeSignerInfos(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackSignerInfosInternal */


/******************************************************************
 * Routines for DistributionPoint
 ******************************************************************/

size_t pgpasn_SizeofDistributionPointInternal(
    PGPASN_DistributionPoint *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            pgpasn_SizeofDistributionPointNameInternal(asnstruct->distributionPoint, PGPASN_TRUE, PGPASN_TRUE)
          + pgpasn_SizeofReasonFlagsInternal(asnstruct->reasons, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofGeneralNamesInternal(asnstruct->cRLIssuer, PGPASN_TRUE, PGPASN_FALSE) ;

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;

} /* pgpasn_SizeofDistributionPointInternal */

void pgpasn_DropInPlaceDistributionPoint(
    PGPASN_CONTEXT *ctx,
    PGPASN_DistributionPoint *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    pgpasn_FreeDistributionPointName(ctx, f->distributionPoint);
    f->distributionPoint = NULL;
    pgpasn_FreeReasonFlags(ctx, f->reasons);
    f->reasons = NULL;
    pgpasn_FreeGeneralNames(ctx, f->cRLIssuer);
    f->cRLIssuer = NULL;
} /* pgpasn_DropInPlaceDistributionPoint */

size_t pgpasn_PackDistributionPointInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_DistributionPoint *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofDistributionPoint(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

  do {

    /* field distributionPoint of DistributionPoint */
    if (asnstruct->distributionPoint != NULL) { /* optional */
        bytesused += PGPASN_PutTag(buf+bytesused, 0xa0 | 0x00, pgpasn_SizeofDistributionPointName(ctx, asnstruct->distributionPoint, PGPASN_TRUE));
        bytesused += pgpasn_PackDistributionPointNameInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->distributionPoint, PGPASN_ID_DistributionPointName, erret) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

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

    /* field cRLIssuer of DistributionPoint */
    if (asnstruct->cRLIssuer != NULL) { /* optional */
        bytesused += pgpasn_PackGeneralNamesInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->cRLIssuer, 0x80 | 0x02, erret ) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackDistributionPointInternal */

size_t pgpasn_UnpkInPlaceDistributionPoint(
    PGPASN_CONTEXT *ctx,
    PGPASN_DistributionPoint *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;

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "DistributionPoint" );

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

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

    PGPASN_TRACE_INCR_LEVEL;
  do {

    /* field distributionPoint of DistributionPoint */
    if (!indef && bytesused >= localsize) {
        PGPASN_TRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PGPASN_TRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    { /* local declaration block*/
        size_t taggeddatasize;
        size_t taggedlocalsize;
        size_t used;

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

        if ((int)taggeddatasize == -1 && used != 0) {
            PGPASN_TRACE_PRINT_TAG(0xa0|0x00, 0x00);
            PGPASN_TRACE_INCR_LEVEL;
            if (asnstruct->distributionPoint != NULL)
                pgpasn_FreeDistributionPointName(ctx, asnstruct->distributionPoint);
            bytesused += pgpasn_UnpackDistributionPointNameInternal(ctx, &(asnstruct->distributionPoint),
                    buf+bytesused, localsize-bytesused, PGPASN_ID_DistributionPointName, erret);
            PGPASN_TRACE_DECR_LEVEL;
            if ( *(buf+bytesused) != 0x00 &&
                 *(buf+bytesused+1) != 0x00 ) {
                PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
                break;
            }
            bytesused += 2;
        }

        else if (taggeddatasize > 0 && used != 0) {
            taggedlocalsize = bytesused + taggeddatasize;
            PGPASN_TRACE_PRINT_TAG(0xa0|0x00, 0x00);
            PGPASN_TRACE_INCR_LEVEL;
            if (asnstruct->distributionPoint != NULL)
                pgpasn_FreeDistributionPointName(ctx, asnstruct->distributionPoint);
            bytesused += pgpasn_UnpackDistributionPointNameInternal(ctx, &(asnstruct->distributionPoint),
                       buf+bytesused, localsize-bytesused, PGPASN_ID_DistributionPointName, erret);
            PGPASN_TRACE_DECR_LEVEL;
            if (bytesused != taggedlocalsize) {
                PGPASN_ERR(kPGPASNError_ErrUnpackTaggedLth);
                break;
            }
        }
    } /* for the local declaration block */
    if (bytesused > localsize || *erret != 0)
        break;

    /* field reasons of DistributionPoint */
    if (!indef && bytesused >= localsize) {
        PGPASN_TRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PGPASN_TRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->reasons != NULL)
        pgpasn_FreeReasonFlags(ctx, asnstruct->reasons);
    bytesused += pgpasn_UnpackReasonFlagsInternal(ctx, &(asnstruct->reasons),
                 buf+bytesused, localsize-bytesused,
                 0x80 | 0x01, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field cRLIssuer of DistributionPoint */
    if (!indef && bytesused >= localsize) {
        PGPASN_TRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PGPASN_TRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->cRLIssuer != NULL)
        pgpasn_FreeGeneralNames(ctx, asnstruct->cRLIssuer);
    bytesused += pgpasn_UnpackGeneralNamesInternal(ctx, &(asnstruct->cRLIssuer),
                 buf+bytesused, localsize-bytesused,
                 0x80 | 0x02, erret);
    if (bytesused > localsize || *erret != 0)
        break;

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceDistributionPoint */

size_t pgpasn_UnpackDistributionPointInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_DistributionPoint **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_DistributionPoint *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewDistributionPoint(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceDistributionPoint(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeDistributionPoint(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackDistributionPointInternal */


/******************************************************************
 * Routines for IssuingDistributionPoint
 ******************************************************************/

size_t pgpasn_SizeofIssuingDistributionPointInternal(
    PGPASN_IssuingDistributionPoint *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            pgpasn_SizeofDistributionPointNameInternal(asnstruct->distributionPoint, PGPASN_TRUE, PGPASN_TRUE)
          + pgpasn_SizeofBOOLEANInternal(asnstruct->onlyContainsUserCerts, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofBOOLEANInternal(asnstruct->onlyContainsCACerts, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofReasonFlagsInternal(asnstruct->onlySomeReasons, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofBOOLEANInternal(asnstruct->indirectCRL, PGPASN_TRUE, PGPASN_FALSE) ;

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;

} /* pgpasn_SizeofIssuingDistributionPointInternal */

void pgpasn_DropInPlaceIssuingDistributionPoint(
    PGPASN_CONTEXT *ctx,
    PGPASN_IssuingDistributionPoint *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    pgpasn_FreeDistributionPointName(ctx, f->distributionPoint);
    f->distributionPoint = NULL;
    pgpasn_FreeBOOLEAN(ctx, f->onlyContainsUserCerts);
    f->onlyContainsUserCerts = NULL;
    pgpasn_FreeBOOLEAN(ctx, f->onlyContainsCACerts);
    f->onlyContainsCACerts = NULL;
    pgpasn_FreeReasonFlags(ctx, f->onlySomeReasons);
    f->onlySomeReasons = NULL;
    pgpasn_FreeBOOLEAN(ctx, f->indirectCRL);
    f->indirectCRL = NULL;
} /* pgpasn_DropInPlaceIssuingDistributionPoint */

size_t pgpasn_PackIssuingDistributionPointInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_IssuingDistributionPoint *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofIssuingDistributionPoint(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

  do {

    /* field distributionPoint of IssuingDistributionPoint */
    if (asnstruct->distributionPoint != NULL) { /* optional */
        bytesused += PGPASN_PutTag(buf+bytesused, 0xa0 | 0x00, pgpasn_SizeofDistributionPointName(ctx, asnstruct->distributionPoint, PGPASN_TRUE));
        bytesused += pgpasn_PackDistributionPointNameInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->distributionPoint, PGPASN_ID_DistributionPointName, erret) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

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

    /* field onlyContainsCACerts of IssuingDistributionPoint */
    if (asnstruct->onlyContainsCACerts != NULL) { /* optional */
        bytesused += pgpasn_PackBOOLEANInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->onlyContainsCACerts, 0x80 | 0x02, erret ) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

    /* field onlySomeReasons of IssuingDistributionPoint */
    if (asnstruct->onlySomeReasons != NULL) { /* optional */
        bytesused += pgpasn_PackReasonFlagsInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->onlySomeReasons, 0x80 | 0x03, erret ) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

    /* field indirectCRL of IssuingDistributionPoint */
    if (asnstruct->indirectCRL != NULL) { /* optional */
        bytesused += pgpasn_PackBOOLEANInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->indirectCRL, 0x80 | 0x04, erret ) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackIssuingDistributionPointInternal */

size_t pgpasn_UnpkInPlaceIssuingDistributionPoint(
    PGPASN_CONTEXT *ctx,
    PGPASN_IssuingDistributionPoint *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;

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "IssuingDistributionPoint" );

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

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

    PGPASN_TRACE_INCR_LEVEL;
  do {

    /* field distributionPoint of IssuingDistributionPoint */
    if (!indef && bytesused >= localsize) {
        PGPASN_TRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PGPASN_TRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    { /* local declaration block*/
        size_t taggeddatasize;
        size_t taggedlocalsize;
        size_t used;

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

        if ((int)taggeddatasize == -1 && used != 0) {
            PGPASN_TRACE_PRINT_TAG(0xa0|0x00, 0x00);
            PGPASN_TRACE_INCR_LEVEL;
            if (asnstruct->distributionPoint != NULL)
                pgpasn_FreeDistributionPointName(ctx, asnstruct->distributionPoint);
            bytesused += pgpasn_UnpackDistributionPointNameInternal(ctx, &(asnstruct->distributionPoint),
                    buf+bytesused, localsize-bytesused, PGPASN_ID_DistributionPointName, erret);
            PGPASN_TRACE_DECR_LEVEL;
            if ( *(buf+bytesused) != 0x00 &&
                 *(buf+bytesused+1) != 0x00 ) {
                PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
                break;
            }
            bytesused += 2;
        }

        else if (taggeddatasize > 0 && used != 0) {
            taggedlocalsize = bytesused + taggeddatasize;
            PGPASN_TRACE_PRINT_TAG(0xa0|0x00, 0x00);
            PGPASN_TRACE_INCR_LEVEL;
            if (asnstruct->distributionPoint != NULL)
                pgpasn_FreeDistributionPointName(ctx, asnstruct->distributionPoint);
            bytesused += pgpasn_UnpackDistributionPointNameInternal(ctx, &(asnstruct->distributionPoint),
                       buf+bytesused, localsize-bytesused, PGPASN_ID_DistributionPointName, erret);
            PGPASN_TRACE_DECR_LEVEL;
            if (bytesused != taggedlocalsize) {
                PGPASN_ERR(kPGPASNError_ErrUnpackTaggedLth);
                break;
            }
        }
    } /* for the local declaration block */
    if (bytesused > localsize || *erret != 0)
        break;

    /* field onlyContainsUserCerts of IssuingDistributionPoint */
    if (!indef && bytesused >= localsize) {
        PGPASN_TRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PGPASN_TRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->onlyContainsUserCerts != NULL)
        pgpasn_FreeBOOLEAN(ctx, asnstruct->onlyContainsUserCerts);
    bytesused += pgpasn_UnpackBOOLEANInternal(ctx, &(asnstruct->onlyContainsUserCerts),
                 buf+bytesused, localsize-bytesused,
                 0x80 | 0x01, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field onlyContainsCACerts of IssuingDistributionPoint */
    if (!indef && bytesused >= localsize) {
        PGPASN_TRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PGPASN_TRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->onlyContainsCACerts != NULL)
        pgpasn_FreeBOOLEAN(ctx, asnstruct->onlyContainsCACerts);
    bytesused += pgpasn_UnpackBOOLEANInternal(ctx, &(asnstruct->onlyContainsCACerts),
                 buf+bytesused, localsize-bytesused,
                 0x80 | 0x02, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field onlySomeReasons of IssuingDistributionPoint */
    if (!indef && bytesused >= localsize) {
        PGPASN_TRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PGPASN_TRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->onlySomeReasons != NULL)
        pgpasn_FreeReasonFlags(ctx, asnstruct->onlySomeReasons);
    bytesused += pgpasn_UnpackReasonFlagsInternal(ctx, &(asnstruct->onlySomeReasons),
                 buf+bytesused, localsize-bytesused,
                 0x80 | 0x03, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field indirectCRL of IssuingDistributionPoint */
    if (!indef && bytesused >= localsize) {
        PGPASN_TRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PGPASN_TRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->indirectCRL != NULL)
        pgpasn_FreeBOOLEAN(ctx, asnstruct->indirectCRL);
    bytesused += pgpasn_UnpackBOOLEANInternal(ctx, &(asnstruct->indirectCRL),
                 buf+bytesused, localsize-bytesused,
                 0x80 | 0x04, erret);
    if (bytesused > localsize || *erret != 0)
        break;

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceIssuingDistributionPoint */

size_t pgpasn_UnpackIssuingDistributionPointInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_IssuingDistributionPoint **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_IssuingDistributionPoint *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewIssuingDistributionPoint(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceIssuingDistributionPoint(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeIssuingDistributionPoint(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackIssuingDistributionPointInternal */


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

size_t pgpasn_SizeofSignedDataInternal(
    PGPASN_SignedData *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            pgpasn_SizeofVersionInternal(&asnstruct->version, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofDigestAlgorithmIdentifiersInternal(&asnstruct->digestAlgorithms, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofContentInfoInternal(&asnstruct->contentInfo, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofCertificatesInternal(asnstruct->certificates, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofCertificateRevocationListsInternal(asnstruct->crls, PGPASN_TRUE, PGPASN_FALSE)
          + pgpasn_SizeofSignerInfosInternal(&asnstruct->signerInfos, PGPASN_TRUE, PGPASN_FALSE) ;

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;

} /* pgpasn_SizeofSignedDataInternal */

void pgpasn_DropInPlaceSignedData(
    PGPASN_CONTEXT *ctx,
    PGPASN_SignedData *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    pgpasn_DropInPlaceVersion(ctx, &(f->version));
    pgpasn_DropInPlaceDigestAlgorithmIdentifiers(ctx, &(f->digestAlgorithms));
    pgpasn_DropInPlaceContentInfo(ctx, &(f->contentInfo));
    pgpasn_FreeCertificates(ctx, f->certificates);
    f->certificates = NULL;
    pgpasn_FreeCertificateRevocationLists(ctx, f->crls);
    f->crls = NULL;
    pgpasn_DropInPlaceSignerInfos(ctx, &(f->signerInfos));
} /* pgpasn_DropInPlaceSignedData */

size_t pgpasn_PackSignedDataInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_SignedData *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) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = pgpasn_SizeofSignedData(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

  do {

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

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

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

    /* field certificates of SignedData */
    if (asnstruct->certificates != NULL) { /* optional */
        bytesused += pgpasn_PackCertificatesInternal(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 += pgpasn_PackCertificateRevocationListsInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->crls, 0x80 | 0x01, erret ) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

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

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun)

    return bytesused;
} /* pgpasn_PackSignedDataInternal */

size_t pgpasn_UnpkInPlaceSignedData(
    PGPASN_CONTEXT *ctx,
    PGPASN_SignedData *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;

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "SignedData" );

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }

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

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

    PGPASN_TRACE_INCR_LEVEL;
  do {

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

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

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

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

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

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

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceSignedData */

size_t pgpasn_UnpackSignedDataInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_SignedData **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_SignedData *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewSignedData(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceSignedData(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeSignedData(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackSignedDataInternal */


/******************************************************************
 * Routines for CRLDistPointsSyntax
 ******************************************************************/

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

    if (asnstruct == NULL)
        return 0;

    lth = asnstruct->n ;
    if (lth > PGPASN_MAX_CRLDistPointsSyntax)
        lth = PGPASN_MAX_CRLDistPointsSyntax;	/* clamp it */
    for (i=0; i<lth; i++)
        body_size += pgpasn_SizeofDistributionPointInternal((asnstruct->elt)[i], PGPASN_TRUE, PGPASN_FALSE);

    if (outerSizeFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1);

    if (expTaggedFlag == PGPASN_TRUE)
        body_size = PGPASN_Tagged(body_size, 1); /* this is seq like */

    return body_size;
} /* pgpasn_SizeofCRLDistPointsSyntaxInternal */

void pgpasn_DropInPlaceCRLDistPointsSyntax(
    PGPASN_CONTEXT *ctx,
    PGPASN_CRLDistPointsSyntax *f)
{
    long i, lth;

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

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

size_t pgpasn_PackCRLDistPointsSyntaxInternal(
    PGPASN_CONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PGPASN_CRLDistPointsSyntax *asnstruct,
    unsigned char tag,
    int *erret )
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;
    long numElem;
    int i;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

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

    /* lth of the block body */
    datasize = pgpasn_SizeofCRLDistPointsSyntax(ctx, asnstruct, PGPASN_FALSE);
    tagsize = 1 + PGPASN_LengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PGPASN_ERR(kPGPASNError_ErrPackBufferTooShort);
        return 0;
    }

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

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

    if (bytesused < datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrPackOverrun);

    return bytesused;
} /* pgpasn_PackCRLDistPointsSyntaxInternal */

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

    PGPASN_TRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE OF", "CRLDistPointsSyntax");

    if (erret == NULL) return 0;

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoBlockPtr);
        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) {
        PGPASN_ERR(kPGPASNError_ErrUnpackInvalidEncoding);
        return 0;
    }
    bytesused ++; /* consume the tag byte */

    PGPASN_TRACE_INCR_LEVEL;

    bytesused += PGPASN_GetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
            asnstruct->n = -1 ; /* note where (-1 treated as 0) */
            PGPASN_TRACE_DECR_LEVEL;
            return 0;
        }
    }

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

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

        if (asnstruct->elt[i] == NULL)
            asnstruct->elt[i] = pgpasn_NewDistributionPoint(ctx);
        if (asnstruct->elt[i] == NULL) {
            PGPASN_ERR(kPGPASNError_ErrOutOfMemory);
            break;
        }
        asnstruct->n = i+1 ; /* note the new element */
        bytesused += pgpasn_UnpkInPlaceDistributionPoint(ctx, asnstruct->elt[i], buf+bytesused,
                            localsize-bytesused, PGPASN_ID_DistributionPoint, erret);
        if (*erret != 0)
            break;
    } /* for */

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

    PGPASN_TRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PGPASN_ERR(kPGPASNError_ErrUnpackUnderrun);

    return bytesused;
} /* pgpasn_UnpkInPlaceCRLDistPointsSyntax */

size_t pgpasn_UnpackCRLDistPointsSyntaxInternal(
    PGPASN_CONTEXT *ctx,
    PGPASN_CRLDistPointsSyntax **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PGPASN_CRLDistPointsSyntax *local = NULL;

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

    if (ctx == NULL) {
        PGPASN_ERR(kPGPASNError_ErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PGPASN_ERR(kPGPASNError_ErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

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

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

    local = pgpasn_NewCRLDistPointsSyntax(ctx); /* carve a block for it */
    bytesused = pgpasn_UnpkInPlaceCRLDistPointsSyntax(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) pgpasn_FreeCRLDistPointsSyntax(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* pgpasn_UnpackCRLDistPointsSyntaxInternal */

