// BEROctet.cpp - Implementation of BEROctet class // // (c) Copyright Schlumberger Technology Corp., unpublished work, created // 1999. This computer program includes Confidential, Proprietary // Information and is a Trade Secret of Schlumberger Technology Corp. All // use, disclosure, and/or reproduction is prohibited unless authorized // in writing. All Rights Reserved. ////////////////////////////////////////////////////////////////////// #include "pkiBEROctet.h" using namespace pki; BEROctet::BEROctet() : m_Octet(0) { } BEROctet::BEROctet(const BEROctet &oct) { m_Octet = 0; *this = oct; } BEROctet::BEROctet(const unsigned char *Buffer, const unsigned long Size) { m_Octet = new unsigned char[Size]; memcpy(m_Octet,Buffer,Size); m_OctetSize = Size; Decode(); } BEROctet::~BEROctet(void) { for(int i=0; i<m_SubOctetList.size(); i++) delete m_SubOctetList[i]; if(m_Octet) delete[] m_Octet; } BEROctet& BEROctet::operator=(const BEROctet &Oct) { if(m_Octet) delete[] m_Octet; for(int i=0; i<m_SubOctetList.size(); i++) delete m_SubOctetList[i]; m_SubOctetList.resize(0); if(Oct.m_Octet) { m_Octet = new unsigned char[Oct.m_OctetSize]; memcpy(m_Octet,Oct.m_Octet,Oct.m_OctetSize); m_OctetSize = Oct.m_OctetSize; Decode(); } else { m_Octet = 0; } return *this; } // Returns the octet data unsigned char *BEROctet::Octet() const { return m_Octet; } unsigned long BEROctet::OctetSize() const { if(!m_Octet) throw Exception(ccBEREmptyOctet); return m_OctetSize; } // Returns true if the octet is constructet, false otherwise bool BEROctet::Constructed() const { if(!m_Octet) throw Exception(ccBEREmptyOctet); return m_PrimConst ? true : false; } // Returns the class of the octet unsigned long BEROctet::Class() const { if(!m_Octet) throw Exception(ccBEREmptyOctet); return m_Class; } // Returns the tag of the octet unsigned long BEROctet::Tag() const { if(!m_Octet) throw Exception(ccBEREmptyOctet); return m_Tag; } // Returns a the data part of the octet unsigned char *BEROctet::Data() const { if(!m_Octet) throw Exception(ccBEREmptyOctet); return m_Data; } // Returns a the size of the data part of the octet unsigned long BEROctet::DataSize() const { if(!m_Octet) throw Exception(ccBEREmptyOctet); return m_DataSize; } // If the octet is a constructed type, this returns list of sub-octets std::vector<BEROctet*> BEROctet::SubOctetList() const { if(!m_Octet) throw Exception(ccBEREmptyOctet); return m_SubOctetList; } // If the octet is an OID, this returns the decoded version, otherwise an empty string std::string BEROctet::ObjectID() const { if(!m_Octet) throw Exception(ccBEREmptyOctet); std::string OID; if(m_Class==0 && m_Tag==6) { char text[40]; unsigned long subid; unsigned char *c = m_Data; unsigned char *Last = m_Octet + m_OctetSize; bool First = true; while(c<Last) { subid = (*c)&0x7F; while((*c)&0x80) { c++; if(c>=Last) throw Exception(ccBERUnexpectedEndOfOctet); if(subid>0x01FFFFFF) throw Exception(ccBEROIDSubIdentifierOverflow); subid = (subid<<7) | ((*c)&0x7F); } if(First) { unsigned long X,Y; if(subid<40) X=0; else if(subid<80) X=1; else X=2; Y = subid-X*40; sprintf(text,"%d %d",X,Y); OID = text; First = false; } else { sprintf(text," %d",subid); OID += text; } c++; } } return OID; } // SearchOID returns all the constructed octets that contain a particular OID void BEROctet::SearchOID(std::string const &OID, std::vector<BEROctet const*> &result) const { for(int i=0; i<m_SubOctetList.size(); i++) { if(m_SubOctetList[i]->Class()==0 && m_SubOctetList[i]->Tag()==6) { if(OID==m_SubOctetList[i]->ObjectID()) { result.push_back(this); } } else if(m_SubOctetList[i]->Constructed()) { m_SubOctetList[i]->SearchOID(OID,result); } } return; } // SearchOIDNext returns all the octets following a particular OID void BEROctet::SearchOIDNext(std::string const &OID, std::vector<BEROctet const*> &result) const { for(int i=0; i<m_SubOctetList.size(); i++) { if(m_SubOctetList[i]->Class()==0 && m_SubOctetList[i]->Tag()==6) { if(OID==m_SubOctetList[i]->ObjectID()) { if((i+1) < m_SubOctetList.size()) result.push_back(m_SubOctetList[i+1]); } } else if(m_SubOctetList[i]->Constructed()) { m_SubOctetList[i]->SearchOIDNext(OID,result); } } return; } // Decodes recursively a BER octet. void BEROctet::Decode() { if(!m_Octet) throw Exception(ccBEREmptyOctet); long BufferSize = m_OctetSize; m_PrimConst = (m_Octet[0]>>5) & 0x1; m_Class = (m_Octet[0]>>6) & 0x3; unsigned char *c = m_Octet; unsigned char *Last = c + BufferSize - 1; m_Tag = *c & 0x1F; if(m_Tag>30) { m_Tag = 0; c++; if(c>Last) throw Exception(ccBERUnexpectedEndOfOctet); while (*c & 0x80) { m_Tag = (m_Tag << 7) | ((*c) & 0x7F); c++; if(c>Last) throw Exception(ccBERUnexpectedEndOfOctet); } if(m_Tag > 0x01FFFFFF) throw Exception(ccBERTagValueOverflow); m_Tag = (m_Tag << 7) | ((*c) & 0x7F); } c++; if(c>Last) throw Exception(ccBERUnexpectedEndOfOctet); long DataSize; if((*c)&0x80) { int n = (*c) & 0x7F; if(n) { DataSize = 0; for(int i=0; i<n; i++) { c++; if(c>Last) throw Exception(ccBERUnexpectedEndOfOctet); if(DataSize>0x007FFFFF) throw Exception(ccBERDataLengthOverflow); DataSize = (DataSize<<8) | (*c); } } else throw Exception(ccBERUnexpectedIndefiniteLength); } else DataSize = *c; c++; m_Data = c; m_DataSize = DataSize; unsigned long OctetSize = DataSize + (m_Data-m_Octet); if(OctetSize>BufferSize) throw Exception(ccBERInconsistentDataLength); m_OctetSize = OctetSize; for(int i=0; i<m_SubOctetList.size(); i++) delete m_SubOctetList[i]; m_SubOctetList.resize(0); if(m_PrimConst) { // Constructed type unsigned char *Data = m_Data; unsigned long DataSize = m_DataSize; while(DataSize) { BEROctet *oct = new BEROctet(Data,DataSize); m_SubOctetList.push_back(oct); Data += oct->OctetSize(); DataSize -=oct->OctetSize(); } } }