/* * Copyright (C) 1997-2005 by Objective Systems, Inc. * * This software is furnished under an open source license and may be * used and copied only in accordance with the terms of this license. * The text of the license may generally be found in the root * directory of this installation in the COPYING file. It * can also be viewed online at the following URL: * * http://www.obj-sys.com/open/license.html * * Any redistributions of this file including modified versions must * maintain this copyright notice. * *****************************************************************************/ #include "asterisk.h" #include "asterisk/lock.h" #include "ooasn1.h" static int decode16BitConstrainedString (OOCTXT* pctxt, Asn116BitCharString* pString, Asn116BitCharSet* pCharSet); static int decodeOctets (OOCTXT* pctxt, ASN1OCTET* pbuffer, ASN1UINT bufsiz, ASN1UINT nbits); static int getComponentLength (OOCTXT* pctxt, ASN1UINT itemBits); int decodeBits (OOCTXT* pctxt, ASN1UINT* pvalue, ASN1UINT nbits) { unsigned char mask; if (nbits == 0) { *pvalue = 0; return ASN_OK; } /* If the number of bits is less than the current bit offset, mask */ /* off the required number of bits and return.. */ if (nbits < (unsigned)pctxt->buffer.bitOffset) { /* Check if buffer contains number of bits requested */ if (pctxt->buffer.byteIndex >= pctxt->buffer.size) return LOG_ASN1ERR (pctxt, ASN_E_ENDOFBUF); pctxt->buffer.bitOffset -= nbits; *pvalue = ((pctxt->buffer.data[pctxt->buffer.byteIndex]) >> pctxt->buffer.bitOffset) & ((1 << nbits) - 1); return ASN_OK; } /* Otherwise, we first need to mask off the remaining bits in the */ /* current byte, followed by a loop to extract bits from full bytes, */ /* followed by logic to mask of remaining bits from the start of */ /* of the last byte.. */ else { /* Check if buffer contains number of bits requested */ int nbytes = (((nbits - pctxt->buffer.bitOffset) + 7) / 8); if ((pctxt->buffer.byteIndex + nbytes) >= pctxt->buffer.size) { return LOG_ASN1ERR (pctxt, ASN_E_ENDOFBUF); } /* first read current byte remaining bits */ mask = ((1 << pctxt->buffer.bitOffset) - 1); *pvalue = (pctxt->buffer.data[pctxt->buffer.byteIndex]) & mask; nbits -= pctxt->buffer.bitOffset; pctxt->buffer.bitOffset = 8; pctxt->buffer.byteIndex++; /* second read bytes from next byteIndex */ while (nbits >= 8) { *pvalue = (*pvalue << 8) | (pctxt->buffer.data[pctxt->buffer.byteIndex]); pctxt->buffer.byteIndex++; nbits -= 8; } /* third read bits & set bitoffset of the byteIndex */ if (nbits > 0) { pctxt->buffer.bitOffset = 8 - nbits; *pvalue = (*pvalue << nbits) | ((pctxt->buffer.data[pctxt->buffer.byteIndex]) >> pctxt->buffer.bitOffset); } return ASN_OK; } } int decodeBitString (OOCTXT* pctxt, ASN1UINT* numbits_p, ASN1OCTET* buffer, ASN1UINT bufsiz) { ASN1UINT bitcnt; int lstat, octidx = 0, stat; Asn1SizeCnst* pSizeList = pctxt->pSizeConstraint; ASN1BOOL doAlign; for (*numbits_p = 0;;) { lstat = decodeLength (pctxt, &bitcnt); if (lstat < 0) return LOG_ASN1ERR (pctxt, lstat); if (bitcnt > 0) { *numbits_p += bitcnt; stat = bitAndOctetStringAlignmentTest (pSizeList, bitcnt, TRUE, &doAlign); if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat); if (doAlign) { stat = decodeByteAlign (pctxt); if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat); } stat = decodeOctets (pctxt, &buffer[octidx], bufsiz - octidx, bitcnt); if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat); } if (lstat == ASN_OK_FRAG) { octidx += (bitcnt / 8); } else break; } return ASN_OK; } int decodeBMPString (OOCTXT* pctxt, ASN1BMPString* pvalue, Asn116BitCharSet* permCharSet) { Asn116BitCharSet charSet; int stat; /* Set character set */ init16BitCharSet (&charSet, BMP_FIRST, BMP_LAST, BMP_ABITS, BMP_UBITS); if (permCharSet) { set16BitCharSet (pctxt, &charSet, permCharSet); } /* Decode constrained string */ stat = decode16BitConstrainedString (pctxt, pvalue, &charSet); if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat); return (stat); } int decodeByteAlign (OOCTXT* pctxt) { if (pctxt->buffer.bitOffset != 8) { pctxt->buffer.byteIndex++; pctxt->buffer.bitOffset = 8; } return ASN_OK; } int decodeConstrainedStringEx (OOCTXT* pctxt, const char** string, const char* charSet, ASN1UINT abits, ASN1UINT ubits, ASN1UINT canSetBits) { int stat; char* tmpstr; ASN1UINT i, idx, len, nbits = abits; /* note: need to save size constraint for use in alignCharStr */ /* because it will be cleared in decodeLength from the context.. */ Asn1SizeCnst* psize = pctxt->pSizeConstraint; /* Decode length */ stat = decodeLength (pctxt, &len); if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat); /* Byte-align */ if (alignCharStr (pctxt, len, nbits, psize)) { stat = decodeByteAlign (pctxt); if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat); } /* Decode data */ tmpstr = (char*) ASN1MALLOC (pctxt, len+1); if (0 != tmpstr) { if (nbits >= canSetBits && canSetBits > 4) { for (i = 0; i < len; i++) { if ((stat = decodeBits (pctxt, &idx, nbits)) == ASN_OK) { tmpstr[i] = (char) idx; } else break; } } else if (0 != charSet) { ASN1UINT nchars = strlen (charSet); for (i = 0; i < len; i++) { if ((stat = decodeBits (pctxt, &idx, nbits)) == ASN_OK) { if (idx < nchars) { tmpstr[i] = charSet[idx]; } else return LOG_ASN1ERR (pctxt, ASN_E_CONSVIO); } else break; } } else stat = ASN_E_INVPARAM; if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat); tmpstr[i] = '\0'; /* add null-terminator */ } else return LOG_ASN1ERR (pctxt, ASN_E_NOMEM); *string = tmpstr; return ASN_OK; } int decodeConsInteger (OOCTXT* pctxt, ASN1INT* pvalue, ASN1INT lower, ASN1INT upper) { ASN1UINT range_value = upper - lower; ASN1UINT adjusted_value; int stat = ASN_OK; if (range_value != ASN1UINT_MAX) { range_value += 1; } if (lower > upper) return ASN_E_RANGERR; else if (lower != upper) { stat = decodeConsWholeNumber (pctxt, &adjusted_value, range_value); if (stat == ASN_OK) { *pvalue = adjusted_value + lower; if (*pvalue < lower || *pvalue > upper) stat = ASN_E_CONSVIO; } } else { *pvalue = lower; } return stat; } int decodeConsUInt8 (OOCTXT* pctxt, ASN1UINT8* pvalue, ASN1UINT lower, ASN1UINT upper) { ASN1UINT range_value, value; ASN1UINT adjusted_value; int stat = ASN_OK; /* Check for special case: if lower is 0 and upper is ASN1UINT_MAX, */ /* set range to ASN1UINT_MAX; otherwise to upper - lower + 1 */ range_value = (lower == 0 && upper == ASN1UINT_MAX) ? ASN1UINT_MAX : upper - lower + 1; if (lower != upper) { ASN1UINT range_bitcnt = 0; /* If range is <= 255, bit-field case (10.5.7a) */ if (range_value <= 255) { range_bitcnt = getUIntBitCount (range_value - 1); } /* If range is exactly 256, one-octet case (10.5.7b) */ else if (range_value == 256) { stat = decodeByteAlign (pctxt); if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat); range_bitcnt = 8; } stat = decodeBits (pctxt, &adjusted_value, range_bitcnt); if (stat == ASN_OK) { value = adjusted_value + lower; if (value < lower || value > upper) stat = ASN_E_CONSVIO; *pvalue = (ASN1OCTET)value; } } else *pvalue = (ASN1OCTET)lower; return stat; } int decodeConsUInt16 (OOCTXT* pctxt, ASN1USINT* pvalue, ASN1UINT lower, ASN1UINT upper) { ASN1UINT range_value, value; ASN1UINT adjusted_value; int stat = ASN_OK; /* Check for special case: if lower is 0 and upper is ASN1UINT_MAX, */ /* set range to ASN1UINT_MAX; otherwise to upper - lower + 1 */ range_value = (lower == 0 && upper == ASN1UINT_MAX) ? ASN1UINT_MAX : upper - lower + 1; if (lower != upper) { stat = decodeConsWholeNumber (pctxt, &adjusted_value, range_value); if (stat == ASN_OK) { value = adjusted_value + lower; /* Verify value is within given range (ED, 1/15/2002) */ if (value < lower || value > upper) stat = ASN_E_CONSVIO; *pvalue = (ASN1USINT) value; } } else *pvalue = (ASN1USINT) lower; return stat; } int decodeConsUnsigned (OOCTXT* pctxt, ASN1UINT* pvalue, ASN1UINT lower, ASN1UINT upper) { ASN1UINT range_value; ASN1UINT adjusted_value; int stat = ASN_OK; /* Check for special case: if lower is 0 and upper is ASN1UINT_MAX, */ /* set range to ASN1UINT_MAX; otherwise to upper - lower + 1 */ range_value = (lower == 0 && upper == ASN1UINT_MAX) ? ASN1UINT_MAX : upper - lower + 1; if (lower != upper) { stat = decodeConsWholeNumber (pctxt, &adjusted_value, range_value); if (stat == ASN_OK) { *pvalue = adjusted_value + lower; if (*pvalue < lower || *pvalue > upper) stat = ASN_E_CONSVIO; } } else *pvalue = lower; return stat; } int decodeConsWholeNumber (OOCTXT* pctxt, ASN1UINT* padjusted_value, ASN1UINT range_value) { ASN1UINT nocts, range_bitcnt; int stat; /* If unaligned, decode non-negative binary integer in the minimum */ /* number of bits necessary to represent the range (10.5.6) */ if (!TRUE) { range_bitcnt = getUIntBitCount (range_value - 1); } /* If aligned, encoding depended on range value (10.5.7) */ else { /* aligned */ /* If range is <= 255, bit-field case (10.5.7a) */ if (range_value <= 255) { range_bitcnt = getUIntBitCount (range_value - 1); } /* If range is exactly 256, one-octet case (10.5.7b) */ else if (range_value == 256) { stat = decodeByteAlign (pctxt); if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat); range_bitcnt = 8; } /* If range > 256 and <= 64k (65535), two-octet case (10.5.7c) */ else if (range_value <= 65536) { stat = decodeByteAlign (pctxt); if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat); range_bitcnt = 16; } /* If range > 64k, indefinite-length case (10.5.7d) */ else { stat = decodeBits (pctxt, &nocts, 2); if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat); stat = decodeByteAlign (pctxt); if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat); range_bitcnt = (nocts + 1) * 8; } } return decodeBits (pctxt, padjusted_value, range_bitcnt); } int decodeDynBitString (OOCTXT* pctxt, ASN1DynBitStr* pBitStr) { ASN1UINT nocts; ASN1OCTET* ptmp; int nbits, stat = ASN_OK; /* If "fast copy" option is not set (ASN1FATSCOPY) or if constructed, * copy the bit string value into a dynamic memory buffer; * otherwise, store the pointer to the value in the decode * buffer in the data pointer argument. */ if (pctxt->flags & ASN1FASTCOPY) { /* check is it possible to do optimized decoding */ ASN1OCTET bit; ASN1UINT byteIndex = pctxt->buffer.byteIndex; /* save byte index */ ASN1USINT bitOffset = pctxt->buffer.bitOffset; /* save bit offset */ stat = decodeByteAlign (pctxt); if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat); stat = DECODEBIT (pctxt, &bit); /* read first bit of length determinant */ if (bit == 1 && stat == ASN_OK) stat = DECODEBIT (pctxt, &bit); /* read second bit */ pctxt->buffer.byteIndex = byteIndex; /* restore byte index */ pctxt->buffer.bitOffset = bitOffset; /* restore bit offset */ /* if either first or second bit != 0 - not fragmented */ if (bit == 0 && stat == ASN_OK) { ASN1UINT bitcnt; stat = decodeLength (pctxt, &bitcnt); if (stat != 0) return LOG_ASN1ERR (pctxt, stat); pBitStr->numbits = bitcnt; if (bitcnt > 0) { pBitStr->data = ASN1BUFPTR (pctxt); stat = moveBitCursor (pctxt, bitcnt); if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat); } else pBitStr->data = 0; return stat; } } nbits = getComponentLength (pctxt, 1); if (nbits < 0) return LOG_ASN1ERR (pctxt, nbits); else if (nbits == 0) { pBitStr->numbits = 0; ptmp = 0; } nocts = (nbits + 7) / 8; /* Allocate memory for the target string */ if (nocts > 0) { ptmp = (ASN1OCTET*) ASN1MALLOC (pctxt, nocts); if (0 == ptmp) return LOG_ASN1ERR (pctxt, ASN_E_NOMEM); /* Call static bit string decode function */ stat = decodeBitString (pctxt, &pBitStr->numbits, ptmp, nocts); } pBitStr->data = ptmp; return stat; } int decodeDynOctetString (OOCTXT* pctxt, ASN1DynOctStr* pOctStr) { ASN1OCTET* ptmp; int nocts, stat; /* If "fast copy" option is not set (ASN1FASTCOPY) or if constructed, * copy the octet string value into a dynamic memory buffer; * otherwise, store the pointer to the value in the decode * buffer in the data pointer argument. */ if (pctxt->flags & ASN1FASTCOPY) { /* check if it is possible to do optimized decoding */ ASN1OCTET bit; ASN1UINT byteIndex = pctxt->buffer.byteIndex; /* save byte index */ ASN1USINT bitOffset = pctxt->buffer.bitOffset; /* save bit offset */ stat = decodeByteAlign (pctxt); if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat); stat = DECODEBIT (pctxt, &bit); /* read first bit of length determinant */ if (bit == 1 && stat == ASN_OK) stat = DECODEBIT (pctxt, &bit); /* read second bit */ pctxt->buffer.byteIndex = byteIndex; /* restore byte index */ pctxt->buffer.bitOffset = bitOffset; /* restore bit offset */ /* if either first or second bit != 0 - not fragmented */ if (bit == 0 && stat == ASN_OK) { ASN1UINT octcnt; stat = decodeLength (pctxt, &octcnt); if (stat != 0) return LOG_ASN1ERR (pctxt, stat); pOctStr->numocts = octcnt; if (octcnt > 0) { pOctStr->data = ASN1BUFPTR (pctxt); stat = moveBitCursor (pctxt, octcnt * 8); if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat); } else pOctStr->data = 0; return stat; } } nocts = getComponentLength (pctxt, 8); if (nocts < 0) return LOG_ASN1ERR (pctxt, nocts); else if (nocts == 0) { pOctStr->numocts = 0; ptmp = 0; } /* Allocate memory for the target string */ else { ptmp = (ASN1OCTET*) ASN1MALLOC (pctxt, nocts); if (0 == ptmp) return LOG_ASN1ERR (pctxt, ASN_E_NOMEM); } /* Call static octet string decode function */ stat = decodeOctetString (pctxt, &pOctStr->numocts, ptmp, nocts); pOctStr->data = ptmp; return stat; } int decodeLength (OOCTXT* pctxt, ASN1UINT* pvalue) { Asn1SizeCnst* pSize; ASN1UINT lower, upper; ASN1BOOL bitValue, extbit; int stat; /* If size constraint is present and extendable, decode extension */ /* bit.. */ if (isExtendableSize(pctxt->pSizeConstraint)) { stat = DECODEBIT (pctxt, &extbit); if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat); } else extbit = 0; /* Now use the value of the extension bit to select the proper */ /* size constraint range specification.. */ pSize = getSizeConstraint (pctxt, extbit); lower = (pSize) ? pSize->lower : 0; upper = (pSize) ? pSize->upper : ASN1UINT_MAX; /* Reset the size constraint in the context block structure */ pctxt->pSizeConstraint = 0; /* If upper limit is less than 64k, constrained case */ if (upper < 65536) { if (lower == upper) { *pvalue = 0; stat = ASN_OK; } else stat = decodeConsWholeNumber (pctxt, pvalue, (upper - lower + 1)); if (stat == ASN_OK) *pvalue += lower; } else { /* unconstrained case OR constrained with upper bound >= 64K*/ stat = decodeByteAlign (pctxt); if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat); stat = DECODEBIT (pctxt, &bitValue); if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat); if (bitValue == 0) { stat = decodeBits (pctxt, pvalue, 7); /* 10.9.3.6 */ if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat); } else { stat = DECODEBIT (pctxt, &bitValue); if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat); if (bitValue == 0) { stat = decodeBits (pctxt, pvalue, 14); /* 10.9.3.7 */ if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat); } else { ASN1UINT multiplier; stat = decodeBits (pctxt, &multiplier, 6); if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat); *pvalue = 16384 * multiplier; stat = ASN_OK_FRAG; } } } return stat; } int decodeObjectIdentifier (OOCTXT* pctxt, ASN1OBJID* pvalue) { ASN1UINT len; int stat, j; unsigned subid; ASN1UINT b; /* Decode unconstrained length */ if ((stat = decodeLength (pctxt, &len)) < 0) { return LOG_ASN1ERR (pctxt, stat); } /* Copy contents to a byte-aligned local buffer */ j = 0; while (len > 0 && stat == ASN_OK) { if (j < ASN_K_MAXSUBIDS) { /* Parse a subidentifier out of the contents field */ pvalue->subid[j] = 0; do { if ((stat = decodeBits (pctxt, &b, 8)) == ASN_OK) { pvalue->subid[j] = (pvalue->subid[j] * 128) + (b & 0x7F); len--; } } while (b & 0x80 && stat == ASN_OK); /* Handle the first subidentifier special case: the first two */ /* sub-id's are encoded into one using the formula (x * 40) + y */ if (j == 0) { subid = pvalue->subid[0]; pvalue->subid[0] = ((subid / 40) >= 2) ? 2 : subid / 40; pvalue->subid[1] = (pvalue->subid[0] == 2) ? subid - 80 : subid % 40; j = 2; } else j++; } else stat = ASN_E_INVOBJID; } pvalue->numids = j; if (stat == ASN_OK && len != 0) stat = ASN_E_INVLEN; return (stat); } static int decodeOctets (OOCTXT* pctxt, ASN1OCTET* pbuffer, ASN1UINT bufsiz, ASN1UINT nbits) { ASN1UINT nbytes = (nbits + 7) / 8 ; ASN1UINT i = 0, j; ASN1UINT rshift = pctxt->buffer.bitOffset; ASN1UINT lshift = 8 - rshift; ASN1UINT nbitsInLastOctet; ASN1OCTET mask; int stat; /* Check to make sure buffer contains number of bits requested */ if ((pctxt->buffer.byteIndex + nbytes) > pctxt->buffer.size) { return LOG_ASN1ERR (pctxt, ASN_E_ENDOFBUF); } /* Check to make sure buffer is big enough to hold requested */ /* number of bits.. */ if (nbytes > bufsiz) { return LOG_ASN1ERR (pctxt, ASN_E_STROVFLW); } /* If on a byte boundary, can do a direct memcpy to target buffer */ if (pctxt->buffer.bitOffset == 8) { memcpy (pbuffer, &pctxt->buffer.data[pctxt->buffer.byteIndex], nbytes); stat = moveBitCursor (pctxt, nbits); if (stat != ASN_OK) return stat; i = nbytes - 1; nbits %= 8; } else { while (nbits >= 8) { /* Transfer lower bits from stream octet to upper bits of */ /* target octet.. */ pbuffer[i] = pctxt->buffer.data[pctxt->buffer.byteIndex++] << lshift; /* Transfer upper bits from next stream octet to lower bits */ /* target octet.. */ pbuffer[i++] |= pctxt->buffer.data[pctxt->buffer.byteIndex] >> rshift; nbits -= 8; } /* Copy last partial byte */ if (nbits >= rshift) { pbuffer[i] = pctxt->buffer.data[pctxt->buffer.byteIndex++] << lshift; nbitsInLastOctet = nbits - rshift; if (nbitsInLastOctet > 0) { pbuffer[i] |= pctxt->buffer.data[pctxt->buffer.byteIndex] >> rshift; } pctxt->buffer.bitOffset = 8 - nbitsInLastOctet; } else if (nbits > 0) { /* nbits < rshift */ pbuffer[i] = pctxt->buffer.data[pctxt->buffer.byteIndex] << lshift; pctxt->buffer.bitOffset = rshift - nbits; } } /* Mask unused bits off of last byte */ if (nbits > 0) { mask = 0; for (j = 0; j < nbits; j++) { mask >>= 1; mask |= 0x80; } pbuffer[i] &= mask; } return ASN_OK; } int decodeOctetString (OOCTXT* pctxt, ASN1UINT* numocts_p, ASN1OCTET* buffer, ASN1UINT bufsiz) { ASN1UINT octcnt; int lstat, octidx = 0, stat; Asn1SizeCnst* pSizeList = pctxt->pSizeConstraint; for (*numocts_p = 0;;) { lstat = decodeLength (pctxt, &octcnt); if (lstat < 0) return LOG_ASN1ERR (pctxt, lstat); if (octcnt > 0) { *numocts_p += octcnt; if (TRUE) { ASN1BOOL doAlign; stat = bitAndOctetStringAlignmentTest (pSizeList, octcnt, FALSE, &doAlign); if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat); if (doAlign) { stat = decodeByteAlign (pctxt); if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat); } } stat = decodeOctets (pctxt, &buffer[octidx], bufsiz - octidx, (octcnt * 8)); if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat); } if (lstat == ASN_OK_FRAG) { octidx += octcnt; } else break; } return ASN_OK; } int decodeOpenType (OOCTXT* pctxt, const ASN1OCTET** object_p2, ASN1UINT* numocts_p) { ASN1DynOctStr octStr; int stat; stat = decodeDynOctetString (pctxt, &octStr); if (stat == ASN_OK) { *numocts_p = octStr.numocts; *object_p2 = octStr.data; } return stat; } int decodeSemiConsInteger (OOCTXT* pctxt, ASN1INT* pvalue, ASN1INT lower) { signed char b; unsigned char ub; ASN1UINT nbytes; int stat; stat = decodeLength (pctxt, &nbytes); if (stat < 0) return LOG_ASN1ERR (pctxt, stat); if (nbytes > 0) { /* Align buffer */ stat = decodeByteAlign (pctxt); if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat); /* Decode first byte into a signed byte value and assign to integer. */ /* This should handle sign extension.. */ stat = decodeOctets (pctxt, (ASN1OCTET*)&b, 1, 8); if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat); *pvalue = b; nbytes--; /* Decode remaining bytes and add to result */ while (nbytes > 0) { stat = decodeOctets (pctxt, (ASN1OCTET*)&ub, 1, 8); if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat); *pvalue = (*pvalue * 256) + ub; nbytes--; } } else { /* nbytes == 0 */ *pvalue = 0; } if (lower > ASN1INT_MIN) *pvalue += lower; return ASN_OK; } int decodeSemiConsUnsigned (OOCTXT* pctxt, ASN1UINT* pvalue, ASN1UINT lower) { ASN1UINT nbytes; int stat; stat = decodeLength (pctxt, &nbytes); if (stat < 0) return LOG_ASN1ERR (pctxt, stat); if (nbytes > 0) { stat = decodeByteAlign (pctxt); if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat); stat = decodeBits (pctxt, pvalue, nbytes * 8); } else *pvalue = 0; *pvalue += lower; return stat; } int decodeSmallNonNegWholeNumber (OOCTXT* pctxt, ASN1UINT* pvalue) { ASN1BOOL bitValue; ASN1UINT len; int ret; if ((ret = DECODEBIT (pctxt, &bitValue)) != ASN_OK) return ret; if (bitValue == 0) { return decodeBits (pctxt, pvalue, 6); /* 10.6.1 */ } else { if ((ret = decodeLength (pctxt, &len)) < 0) return ret; if ((ret = decodeByteAlign (pctxt)) != ASN_OK) return ret; return decodeBits (pctxt, pvalue, len*8); } } int decodeVarWidthCharString (OOCTXT* pctxt, const char** pvalue) { int stat; ASN1OCTET* tmpstr; ASN1UINT len; /* note: need to save size constraint for use in alignCharStr */ /* because it will be cleared in decodeLength from the context.. */ Asn1SizeCnst* psize = pctxt->pSizeConstraint; /* Decode length */ stat = decodeLength (pctxt, &len); if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat); /* Byte-align */ if (alignCharStr (pctxt, len, 8, psize)) { stat = decodeByteAlign (pctxt); if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat); } /* Decode data */ tmpstr = (ASN1OCTET*) ASN1MALLOC (pctxt, len + 1); if (0 != tmpstr) { if ((stat = decodeOctets (pctxt, tmpstr, len, len * 8)) != ASN_OK) return LOG_ASN1ERR (pctxt, stat); tmpstr[len] = '\0'; /* add null-terminator */ } else return LOG_ASN1ERR (pctxt, ASN_E_NOMEM); *pvalue = (char*)tmpstr; return ASN_OK; } static int decode16BitConstrainedString (OOCTXT* pctxt, Asn116BitCharString* pString, Asn116BitCharSet* pCharSet) { ASN1UINT i, idx, nbits = pCharSet->alignedBits; int stat; /* Decode length */ stat = decodeLength (pctxt, &pString->nchars); if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat); /* Byte-align */ stat = decodeByteAlign (pctxt); if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat); /* Decode data */ pString->data = (ASN116BITCHAR*) ASN1MALLOC (pctxt, pString->nchars*sizeof(ASN116BITCHAR)); if (pString->data) { for (i = 0; i < pString->nchars; i++) { stat = decodeBits (pctxt, &idx, nbits); if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat); pString->data[i] = (pCharSet->charSet.data == 0) ? idx + pCharSet->firstChar : pCharSet->charSet.data[idx]; } } else return LOG_ASN1ERR (pctxt, ASN_E_NOMEM); return ASN_OK; } static int getComponentLength (OOCTXT* pctxt, ASN1UINT itemBits) { OOCTXT lctxt; ASN1UINT len, totalLen = 0; int stat; stat = initSubContext (&lctxt, pctxt); if (stat != ASN_OK) return LOG_ASN1ERR (pctxt, stat); stat = setPERBufferUsingCtxt (&lctxt, pctxt); if (stat != ASN_OK) { freeContext (&lctxt); return LOG_ASN1ERR (pctxt, stat); } lctxt.pSizeConstraint = pctxt->pSizeConstraint; for (;;) { stat = decodeLength (&lctxt, &len); if (stat < 0) { freeContext (&lctxt); return LOG_ASN1ERR (pctxt, stat); } totalLen += len; if (stat == ASN_OK_FRAG) { stat = moveBitCursor (&lctxt, len * itemBits); if (stat != ASN_OK) { freeContext (&lctxt); return LOG_ASN1ERR (pctxt, stat); } } else break; } freeContext (&lctxt); return totalLen; } int moveBitCursor (OOCTXT* pctxt, int bitOffset) { int currBitOffset = (pctxt->buffer.byteIndex * 8) + (8 - pctxt->buffer.bitOffset); currBitOffset += bitOffset; pctxt->buffer.byteIndex = (currBitOffset / 8); pctxt->buffer.bitOffset = 8 - (currBitOffset % 8); if (pctxt->buffer.byteIndex > pctxt->buffer.size) { return (ASN_E_ENDOFBUF); } return ASN_OK; }