/* * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved. * * The contents of this file constitute Original Code as defined in and are * subject to the Apple Public Source License Version 1.2 (the 'License'). * You may not use this file except in compliance with the License. Please obtain * a copy of the License at http://www.apple.com/publicsource and read it before * using this file. * * This Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the * specific language governing rights and limitations under the License. */ // file: .../c++-lib/src/asn-bits.C - AsnBits (ASN.1 BIT STRING) Type // // Mike Sample // 92/07/02 // Copyright (C) 1992 Michael Sample and the University of British Columbia // // This library is free software; you can redistribute it and/or // modify it provided that this copyright/license information is retained // in original form. // // If you modify this file, you must clearly indicate your changes. // // This source code is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // // $Header: /cvs/Darwin/Security/SecuritySNACCRuntime/c++-lib/c++/asn-bits.cpp,v 1.4 2002/03/21 05:38:44 dmitch Exp $ // $Log: asn-bits.cpp,v $ // Revision 1.4 2002/03/21 05:38:44 dmitch // Radar 2868524: no more setjmp/longjmp in SNACC-generated code. // // Revision 1.3.44.1 2002/03/20 00:36:48 dmitch // Radar 2868524: SNACC-generated code now uses throw/catch instead of setjmp/longjmp. // // Revision 1.3 2001/06/28 23:36:11 dmitch // Removed SccsId statics. numToHexCharTblG table now const. Radar 2705410. // // Revision 1.2 2001/06/27 23:09:14 dmitch // Pusuant to Radar 2664258, avoid all cerr-based output in NDEBUG configuration. // // Revision 1.1.1.1 2001/05/18 23:14:05 mb // Move from private repository to open source repository // // Revision 1.3 2001/05/05 00:59:17 rmurphy // Adding darwin license headers // // Revision 1.2 2000/12/07 22:15:49 dmitch // Thread-safe mods: added a local StrStk strStkG to the routines which need it. // // Revision 1.1 2000/06/15 18:44:57 dmitch // These snacc-generated source files are now checked in to allow cross-platform build. // // Revision 1.2 2000/06/08 20:05:34 dmitch // Mods for X port. These files are actually machine generated and probably don't need to be in CVS.... // // Revision 1.1.1.1 2000/03/09 01:00:05 rmurphy // Base Fortissimo Tree // // Revision 1.3 1999/03/21 02:07:35 mb // Added Copy to every AsnType. // // Revision 1.2 1999/02/26 00:23:39 mb // Fixed for Mac OS 8 // // Revision 1.1 1999/02/25 05:21:50 mb // Added snacc c++ library // // Revision 1.9 1997/08/27 15:55:15 wan // GetBit now returns 0 or 1, not 0 or <#bit>, even if bool type is emulated. // // Revision 1.8 1997/02/28 13:39:44 wan // Modifications collected for new version 1.3: Bug fixes, tk4.2. // // Revision 1.7 1997/01/01 20:19:01 rj // dereferencing pointer to member function is neither necessary nor allowed // // Revision 1.6 1995/08/17 15:37:49 rj // set Tcl's errorCode variable // // Revision 1.5 1995/07/24 20:09:07 rj // use memzero that is defined in .../snacc.h to use either memset or bzero. // use memcmpeq that is defined in .../snacc.h to use either memcmp or bcmp. // // call constructor with additional pdu and create arguments. // // #if TCL ... #endif wrapped into #if META ... #endif // // changed `_' to `-' in file names. // // Revision 1.4 1994/10/08 04:18:21 rj // code for meta structures added (provides information about the generated code itself). // // code for Tcl interface added (makes use of the above mentioned meta code). // // virtual inline functions (the destructor, the Clone() function, BEnc(), BDec() and Print()) moved from inc/*.h to src/*.C because g++ turns every one of them into a static non-inline function in every file where the .h file gets included. // // made Print() const (and some other, mainly comparison functions). // // several `unsigned long int' turned into `size_t'. // // Revision 1.3 1994/08/31 23:37:57 rj // TRUE turned into true // // Revision 1.2 1994/08/28 10:01:11 rj // comment leader fixed. // // Revision 1.1 1994/08/28 09:20:57 rj // first check-in. for a list of changes to the snacc-1.1 distribution please refer to the ChangeLog. #include "asn-config.h" #include "asn-len.h" #include "asn-tag.h" #include "asn-type.h" #include "asn-bits.h" #include "str-stk.h" #ifndef __APPLE__ /* OS X - thread safe - the only routine which uses this allocates * it on the stack */ extern StrStk strStkG; unsigned short int strStkUnusedBitsG; #endif /* __APPLE__ */ const char numToHexCharTblG[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; AsnBits::~AsnBits() { delete bits; } AsnType *AsnBits::Clone() const { return new AsnBits; } AsnType *AsnBits::Copy() const { return new AsnBits (*this); } // Initializes the bits string with a bit string numBits in length. // All bits are zeroed. void AsnBits::Set (size_t numBits) { bitLen = numBits; size_t octetLen = (bitLen+7)/8; #ifndef _IBM_ENC_ bits = Asn1Alloc (octetLen); #else bits = (char *) mem_mgr_ptr->Get (octetLen); // Guido Grassel, 11.8.93 #endif /* _IBM_ENC_ */ memzero (bits, octetLen); // init to zeros } // initializes a BIT STRING with the given string and bit length // Copies the bits from bitsOcts. void AsnBits::Set (const char *bitOcts, size_t numBits) { if (bitOcts != bits) { bitLen = numBits; size_t octetLen = (bitLen+7)/8; #ifndef _IBM_ENC_ bits = new char[octetLen]; #else bits = (char *) mem_mgr_ptr->Get (octetLen); // Guido Grassel, 11.8.93 #endif /* _IBM_ENC_ */ memcpy (bits, bitOcts, octetLen); } } // initializes a BIT STRING by copying another BIT STRING's bits void AsnBits::Set (const AsnBits &b) { if (&b != this) { bitLen = b.bitLen; size_t octetLen = (bitLen+7)/8; #ifndef _IBM_ENC_ bits = new char[octetLen]; #else bits = (char *) mem_mgr_ptr->Get (octetLen); // Guido Grassel, 11.8.93 #endif /* _IBM_ENC_ */ memcpy (bits, b.bits, octetLen); } } // Initializes the bits string with a bit string numBits in length. // All bits are zeroed. void AsnBits::ReSet (size_t numBits) { #ifndef _IBM_ENC_ delete bits; Set (numBits); #else mem_mgr_ptr->Put ((void *) bits); // Guido Grassel, 11.8.93 Set (numBits); #endif /* _IBM_ENC_ */ } // frees old bits value and then re-initializes the // BIT STRING with the given string and bit length // Copies the bitOcts into bits. void AsnBits::ReSet (const char *bitOcts, size_t numBits) { if (bitOcts != bits) { #ifndef _IBM_ENC_ delete bits; Set (bitOcts, numBits); #else mem_mgr_ptr->Put ((void *) bits); // Guido Grassel, 11.8.93 Set (bitOcts, numBits); #endif /* _IBM_ENC_ */ } } // frees old bits value and then re-initializes the // BIT STRING by copying another BIT STRING's bits void AsnBits::ReSet (const AsnBits &b) { if (&b != this) // avoid b = b; probs { #ifndef _IBM_ENC_ delete bits; Set (b); #else mem_mgr_ptr->Put ((void *) bits); // Guido Grassel, 11.8.93 Set (b); #endif /* _IBM_ENC_ */ } } // Returns true if the given BIT STRING is the same as this one bool AsnBits::BitsEquiv (const AsnBits &ab) const { size_t octetsLessOne = (bitLen-1)/8; size_t octetBits = 7 - (bitLen % 8); if (!bitLen && !ab.bitLen) return true; // trailing bits may not be significant return bitLen == ab.bitLen && !memcmpeq (bits, ab.bits, octetsLessOne) && (bits[octetsLessOne] & (0xFF << octetBits)) == (ab.bits[octetsLessOne] & (0xFF << octetBits)); } /* AsnBits::BitsEquiv */ // set given bit to 1. Most signif. bit is bit 0, least signif bit is bitLen-1 void AsnBits::SetBit (size_t bit) { if (bit < bitLen) { size_t octet = bit/8; size_t octetsBit = 7 - (bit % 8); // bit zero is first/most sig bit in octet bits[octet] |= 1 << octetsBit; } #ifdef DEBUG else Asn1Errror << "AsnBits::SetBit: ERROR - bit larger than bit string" << endl; #endif } /* AsnBits::SetBit */ // Clr bit. Most signif. bit is bit 0, least signif bit is bitLen-1 void AsnBits::ClrBit (size_t bit) { if (bit < bitLen) { size_t octet = bit/8; size_t octetsBit = 7 - (bit % 8); // bit zero is first/most sig bit in octet bits[octet] &= ~(1 << octetsBit); } #ifdef DEBUG else Asn1Errror << "AsnBits::ClrBit: ERROR - bit larger than bit string" << endl; #endif } /* AsnBits::ClrBit */ // returns given bit. Most signif. bit is bit 0, least signif bit is bitLen-1. // Returns false if the givnen bit index is out of range. bool AsnBits::GetBit (size_t bit) const { if (bit < bitLen) { size_t octet = bit/8; size_t octetsBit = 7 - (bit % 8); // bit zero is first/most sig bit in octet return !!(bits[octet] & (1 << octetsBit)); } #ifdef DEBUG else Asn1Errror << "AsnBits::GetBit: ERROR - bit larger than bit string" << endl; #endif return false; } /* AsnBits::GetBit */ // Encoded the content (included unused bits octet) of the BIT STRING // to the given buffer. AsnLen AsnBits::BEncContent (BUF_TYPE b) { size_t byteLen = (bitLen+7)/8; b.PutSegRvs (bits, byteLen); size_t unusedBits = (bitLen % 8); if (unusedBits != 0) unusedBits = 8 - unusedBits; b.PutByteRvs (unusedBits); return byteLen + 1; } /* AsnBits::BEncContent */ // Decodes a BER BIT STRING from the given buffer and stores // the value in this object. void AsnBits::BDecContent (BUF_TYPE b, AsnTag tagId, AsnLen elmtLen, AsnLen &bytesDecoded, ENV_TYPE env) { // char *tmp; /* * tagId is encoded tag shifted into long int. * if CONS bit is set then constructed bit string */ if (tagId & 0x20000000) BDecConsBits (b, elmtLen, bytesDecoded, env); else /* primitive octet string */ { bytesDecoded += elmtLen; elmtLen--; bitLen = (elmtLen * 8) - (unsigned int)b.GetByte(); #ifndef _IBM_ENC_ bits = Asn1Alloc (elmtLen); #else bits = (char *) mem_mgr_ptr->Get (elmtLen); // Guido Grassel, 11.8.93 #endif /* _IBM_ENC_ */ b.CopyOut (bits, elmtLen); if (b.ReadError()) { Asn1Error << "BDecBitString: ERROR - decoded past end of data" << endl; #if SNACC_EXCEPTION_ENABLE SnaccExcep::throwMe(-1); #else longjmp (env, -1); #endif } } } /* AsnBits::BDecContent */ AsnLen AsnBits::BEnc (BUF_TYPE b) { AsnLen l; l = BEncContent (b); l += BEncDefLen (b, l); l += BEncTag1 (b, UNIV, PRIM, BITSTRING_TAG_CODE); return l; } void AsnBits::BDec (BUF_TYPE b, AsnLen &bytesDecoded, ENV_TYPE env) { AsnLen elmtLen; AsnTag tag; tag = BDecTag (b, bytesDecoded, env); if ((tag != MAKE_TAG_ID (UNIV, PRIM, BITSTRING_TAG_CODE)) && (tag != MAKE_TAG_ID (UNIV, CONS, BITSTRING_TAG_CODE))) { Asn1Error << "AsnBits::BDec: ERROR tag on BIT STRING is wrong." << endl; #if SNACC_EXCEPTION_ENABLE SnaccExcep::throwMe(-50); #else longjmp (env,-50); #endif } elmtLen = BDecLen (b, bytesDecoded, env); BDecContent (b, tag, elmtLen, bytesDecoded, env); } /* * Used to concatentate constructed bit strings when decoding. * * fills string stack with references to the pieces of a * construced bit string. sets strStkUnusedBitsG appropriately. * and strStkTotalByteLenG to bytelen needed to hold the bitstring */ #ifdef __APPLE__ void AsnBits::FillBitStringStk (BUF_TYPE b, AsnLen elmtLen0, AsnLen &bytesDecoded, ENV_TYPE env, StrStk &strStkG, unsigned short int &strStkUnusedBitsG) #else void AsnBits::FillBitStringStk (BUF_TYPE b, AsnLen elmtLen0, AsnLen &bytesDecoded, ENV_TYPE env) #endif { size_t refdLen; size_t totalRefdLen; char *strPtr; AsnLen totalElmtsLen1 = 0; unsigned long int tagId1; AsnLen elmtLen1; size_t lenToRef; // size_t unusedBits; for (; (totalElmtsLen1 < elmtLen0) || (elmtLen0 == INDEFINITE_LEN); ) { tagId1 = BDecTag (b, totalElmtsLen1, env); if ((tagId1 == EOC_TAG_ID) && (elmtLen0 == INDEFINITE_LEN)) { BDEC_2ND_EOC_OCTET (b, totalElmtsLen1, env); break; } elmtLen1 = BDecLen (b, totalElmtsLen1, env); if (tagId1 == MAKE_TAG_ID (UNIV, PRIM, BITSTRING_TAG_CODE)) { /* * primitive part of string, put references to piece (s) in * str stack */ /* * get unused bits octet */ if (strStkUnusedBitsG != 0) { /* * whoa - only allowed non-octed aligned bits on * on last piece of bits string */ Asn1Error << "BDecConsBitString: ERROR - a component of a constructed BIT STRING that is not the last has non-zero unused bits" << endl; #if SNACC_EXCEPTION_ENABLE SnaccExcep::throwMe(-2); #else longjmp (env, -2); #endif } if (elmtLen1 != 0) strStkUnusedBitsG = b.GetByte(); totalRefdLen = 0; lenToRef =elmtLen1-1; /* remove one octet for the unused bits oct*/ refdLen = lenToRef; while (1) { strPtr = b.GetSeg (&refdLen); strStkG.Push (strPtr, refdLen); totalRefdLen += refdLen; if (totalRefdLen == lenToRef) break; /* exit this while loop */ if (refdLen == 0) /* end of data */ { Asn1Error << "BDecConsOctetString: ERROR - expecting more data" << endl; #if SNACC_EXCEPTION_ENABLE SnaccExcep::throwMe(-3); #else longjmp (env, -3); #endif } refdLen = lenToRef - totalRefdLen; } totalElmtsLen1 += elmtLen1; } else if (tagId1 == MAKE_TAG_ID (UNIV, CONS, BITSTRING_TAG_CODE)) { /* * constructed octets string embedding in this constructed * octet string. decode it. */ FillBitStringStk (b, elmtLen1, totalElmtsLen1, env #ifdef __APPLE__ , strStkG, strStkUnusedBitsG #endif ); } else /* wrong tag */ { Asn1Error << "BDecConsBitString: ERROR - decoded non-BIT STRING tag inside a constructed BIT STRING" << endl; #if SNACC_EXCEPTION_ENABLE SnaccExcep::throwMe(-4); #else longjmp (env, -4); #endif } } /* end of for */ bytesDecoded += totalElmtsLen1; } /* FillBitStringStk */ /* * decodes a seq of universally tagged bits until either EOC is * encountered or the given len decoded. Return them in a * single concatenated bit string */ void AsnBits::BDecConsBits (BUF_TYPE b, AsnLen elmtLen, AsnLen &bytesDecoded, ENV_TYPE env) { #ifdef __APPLE__ StrStk strStkG(128, 64); unsigned short int strStkUnusedBitsG; #endif strStkG.Reset(); strStkUnusedBitsG = 0; /* * decode each piece of the octet string, puting * an entry in the octet/bit string stack for each */ FillBitStringStk (b, elmtLen, bytesDecoded, env, strStkG, strStkUnusedBitsG); /* alloc single str long enough for combined bitstring */ bitLen = strStkG.totalByteLen*8 - strStkUnusedBitsG; #ifndef _IBM_ENC_ bits = Asn1Alloc (strStkG.totalByteLen); #else bits = (char *) mem_mgr_ptr->Get (strStkG.totalByteLen); // Guido Grassel, 11.8.93 #endif /* _IBM_ENC_ */ strStkG.CopyOut (bits); } /* BDecConsBits */ // prints the BIT STRING to the given ostream. void AsnBits::Print (ostream &os) const { #ifndef NDEBUG size_t octetLen = (bitLen+7)/8; os << "'"; for (unsigned i = 0; i < octetLen; i++) os << TO_HEX (bits[i] >> 4) << (TO_HEX (bits[i])); os << "'H -- BIT STRING bitlen = " << bitLen << " --"; #endif /* NDEBUG */ } #if META const AsnBitsTypeDesc AsnBits::_desc (NULL, NULL, false, AsnTypeDesc::BIT_STRING, NULL, NULL); const AsnTypeDesc *AsnBits::_getdesc() const { return &_desc; } #if TCL int AsnBits::TclGetVal (Tcl_Interp *interp) const { Tcl_ResetResult(interp); for (int i=0; igetmodule()->name, ".", _getdesc()->getname(), NULL); Tcl_SetErrorCode (interp, "SNACC", "ILLBIT", NULL); return TCL_ERROR; } ReSet (i); for (i=0, p=valstr; i